in react fiber, all relevant logic is structured in these three phases, which correspond to these three files:
ReactFiberBeginWork.jsReactFiberCompleteWork.jsReactFiberCommitWork.jsthey live in react-reconciler link
to have a mental map of what each bit does in React, here's some elements (jsx + html):
<App>
<Header>
<div>
<h1>
<strong>Tie</strong> <a>tle</a>
</h1>
<h3>subtitle</h3>
<span>description</span>
</div>
</Header>
<Content />
</App>ReactFiberBeginWorkReactFiberCompleteWorkReactFiberCommitWorksmoosh-test.js
"use strict";
let React;
let ReactDOM;
let ReactDOMServer;
describe("React Smoosh", () => {
beforeEach(() => {
React = require("react");
ReactDOM = require("react-dom");
ReactDOMServer = require("react-dom/server");
});
it("works", () => {
function Dialog({ children }) {
return (
<div>
<div>
<p>Hello</p>
</div>
<div>
<div>{children}</div>
</div>
</div>
);
}
function Button({ children }) {
return <button>{children}</button>;
}
function App() {
return (
<div>
<div>
<Dialog>
<Button>Click me</Button>
</Dialog>
</div>
</div>
);
}
const container = document.createElement("div");
ReactDOM.render(<App />, container);
expect(container.innerHTML).toBe("<p>Hello</p><button>Click me</button>");
});
});Work performed on React
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on null
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on function App() {
return (
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 35 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 36 } },
React.createElement(Dialog, { __source: { fileName: _jsxFileName, lineNumber: 37 } },
React.createElement(Button, { __source: { fileName: _jsxFileName, lineNumber: 38 } }, 'Click me')))));
}
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on function Dialog(_ref) {var children = _ref.children;
return (
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 20 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 21 } },
React.createElement('p', { __source: { fileName: _jsxFileName, lineNumber: 22 } }, 'Hello')),
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 24 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 25 } }, children))));
}
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on p
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on p
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on div
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on function Button(_ref2) {var children = _ref2.children;
return React.createElement('button', { __source: { fileName: _jsxFileName, lineNumber: 31 } }, children);
}
console.log packages/react-reconciler/src/ReactFiberBeginWork.js:2762
begin work on button
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on button
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on function Button(_ref2) {var children = _ref2.children;
return React.createElement('button', { __source: { fileName: _jsxFileName, lineNumber: 31 } }, children);
}
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on function Dialog(_ref) {var children = _ref.children;
return (
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 20 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 21 } },
React.createElement('p', { __source: { fileName: _jsxFileName, lineNumber: 22 } }, 'Hello')),
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 24 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 25 } }, children))));
}
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on div
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on function App() {
return (
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 35 } },
React.createElement('div', { __source: { fileName: _jsxFileName, lineNumber: 36 } },
React.createElement(Dialog, { __source: { fileName: _jsxFileName, lineNumber: 37 } },
React.createElement(Button, { __source: { fileName: _jsxFileName, lineNumber: 38 } }, 'Click me')))));
}
console.log packages/react-reconciler/src/ReactFiberCompleteWork.js:628
complete work on nullwhen this is done, a function on ReactFiberCommitWork.js is called and the DOM is updated.
updateHostComponent handles all html tags
the core work loop that you will often see in React is:
appendAllChildren = function (
parent: Instance,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean
) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendInitialChild(parent, node.stateNode);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};this is written as a while loop for performance on the js stack but if written as a recursive function, it goes like this:
function doSomething(fiber) {
// do stuff depending on fiber.tag
if (fiber.child) {
doSomething(fiber.child);
}
if (fiber.sibling) {
doSomething(fiber.sibling);
}
}