How Component vs Function Calls Change React's Fiber Tree and Diff Process
This article explains the three key differences between using a custom React component as a JSX element versus calling it as a plain function, covering extra Fiber node creation, distinct execution timing, and how the diff algorithm treats the resulting nodes.
Introduction
When developing with React, developers can invoke a custom component either as a JSX element (component style) or as a regular function (function style). Although both render the same UI, the underlying React engine processes them differently.
Code Examples
App.jsx – Component Style
function MyComponent() {
return <div>Hello Guming!</div>;
}
function App() {
return (
<div className="App">
<MyComponent />
</div>
);
}
export default App;App.jsx – Function Style
function MyComponent() {
return <div>Hello Guming!</div>;
}
function App() {
return (
<div className="App">
{MyComponent()}
</div>
);
}
export default App;Both snippets need Babel compilation before execution.
Compiled Output
// Component style
function MyComponent() {
return React.createElement("div", null, "Hello Guming!");
};
function App() {
return React.createElement(
"div",
{ className: "App" },
React.createElement(MyComponent, null)
);
}
export default App;
// Function style
function MyComponent() {
return React.createElement("div", null, "Hello Guming!");
};
function App() {
return React.createElement(
"div",
{ className: "App" },
MyComponent()
);
}
export default App;React.createElement takes three arguments: type (element type), config (props), and children (child nodes).
Fiber Tree Generation Differences
React builds a Fiber tree from the ReactElements. During an update, a new workInProgress tree is created, and the render phase is split into a "beginWork" (recursive) stage and a "completeWork" (bubble) stage.
"BeginWork" Phase
"CompleteWork" Phase
When using the component style, an extra Fiber node for MyComponent is created:
The MyComponent Fiber node has tag = FunctionComponent, so during completeWork it returns null instead of creating a DOM element.
Component Function Execution Timing
For a FunctionComponent, the Fiber node’s type points to the component function itself. During beginWork, React calls mountIndeterminateComponent on the initial render and updateFunctionComponent on updates, both of which invoke renderWithHooks. The following diagram shows the call stack for the component style:
When the component is used as a plain function, the beginWork node is the App Fiber node instead:
Algorithmic Differences
1. Bailout Strategy – Node Reuse
During an update, React may skip work on a subtree if the following conditions are met:
Old and new props are identical.
Node type has not changed.
No updates exist for the node.
Context has not changed.
If these hold, the subtree’s beginWork is bypassed.
2. Diff Algorithm
The core diff logic lives in reconcileSingleElement. A simplified version is shown below:
function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
// ...key matching logic...
if (child.key === key) {
var elementType = element.type;
if (elementType === REACT_FRAGMENT_TYPE) {
// handle fragment
} else {
if (child.elementType === elementType || isCompatibleFamilyForHotReloading(child, element) ||
(typeof elementType === 'object' && elementType !== null && elementType.$$typeof === REACT_LAZY_TYPE && resolveLazy(elementType) === child.type)) {
// reuse existing fiber
}
}
// ...other cases...
}
child = child.sibling;
}
// create new fiber if no match
}When the component style is used, the MyComponent Fiber node is omitted from the diff because its child property is null. Consequently, it does not affect the final diff result.
Conclusion
Component style creates one additional Fiber node compared to function style.
The execution timing of the component function differs between the two approaches.
During the diff phase, the Fiber node generated by the component style is ignored.
Even though the bailout logic performs an extra node comparison, the overall rendering outcome remains unchanged.
Both approaches ultimately follow React’s Fiber‑based workflow, but the internal structures and some intermediate steps differ.
Goodme Frontend Team
Regularly sharing the team's insights and expertise in the frontend field
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
