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.

Goodme Frontend Team
Goodme Frontend Team
Goodme Frontend Team
How Component vs Function Calls Change React's Fiber Tree and Diff Process

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

BeginWork diagram
BeginWork diagram

"CompleteWork" Phase

CompleteWork diagram
CompleteWork diagram

When using the component style, an extra Fiber node for MyComponent is created:

MyComponent Fiber node
MyComponent Fiber node

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:

Component call stack
Component call stack

When the component is used as a plain function, the beginWork node is the App Fiber node instead:

Function call stack
Function call stack

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.

ReActFiberDiff AlgorithmComponent vs Function
Goodme Frontend Team
Written by

Goodme Frontend Team

Regularly sharing the team's insights and expertise in the frontend field

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.