Setting the background

Here’s a simple application that I’ll use throughout the series. We have a button that simply increments a number rendered on the screen:

And here’s the implementation:

You can play with it here. As you can see, it’s a simple component that returns two child elements button and span from the render method. As soon as you click on the button, the state of the component is updated inside the handler. This, in turn, results in the text update for the span element.

There are various activities React performs during reconciliation. For example, here are the high-level operations React performs during the first render and after state update in our simple application:

updates count property in the state of ClickCounter

property in the of retrieves and compares children of ClickCounter and their props

and their props updates props for the span element

There are other activities performed during reconciliation like calling lifecycle methods or updating refs. All these activities are collectively referred to as “work” in the Fiber architecture. The type of work usually depends on the type of React element. For example, for a class component, React needs to create an instance, while it doesn’t do that for a functional component. As you know, we have many kinds of elements in React, e.g. class and functional components, host components (DOM nodes), portals etc. The type of React element is defined by the first parameter to the createElement function. This function is generally used in the render method to create an element.

Before we begin our exploration of the activities and the main fiber algorithm, let’s first get ourselves familiar with the data structures used internally by React.

From React Elements to Fiber nodes

Every component in React has a UI representation we can call a view or a template that’s returned from the render method. Here’s the template for our ClickCounter component:

React Elements

Once a template goes through the JSX compiler, you end up with a bunch of React elements. This is what’s really returned from the render method of React components, not HTML. Since we’re not required to use JSX, the render method for our ClickCounter component could be re-written like this:

The calls to React.createElement in the render method will create two data structures like this:

You can see that React adds the property $$typeof to these objects to uniquely identify them as React elements. Then we have properties type , key and props that describe the element. The values are taken from what you pass to the React.createElement function. Notice how React represents text content as children of the span and button nodes. And how the click handler is part of the button element props. There are other fields on React elements like the ref field that are beyond the scope of this article.

The React element for ClickCounter doesn’t have any props or a key:

Fiber nodes

During reconciliation data from every React element returned from the render method is merged into the tree of fiber nodes. Every React element has a corresponding fiber node. Unlike React elements, fibers aren’t re-created on every render. These are mutable data structures that hold components state and DOM.

We discussed earlier that depending on the type of a React element the framework needs to perform different activities. In our sample application, for the class components ClickCounter it calls lifecycle methods and the render method, whereas for the span host component (DOM node) it performs DOM mutation. So each React element is converted into a Fiber node of corresponding type that describes the work that needs to be done.

You can think of a fiber as a data structure that represents some work to do or, in other words, a unit of work. Fiber’s architecture also provides a convenient way to track, schedule, pause and abort the work.

When a React element is converted into a fiber node for the first time, React uses the data from the element to create a fiber in the createFiberFromTypeAndProps function. In the consequent updates React reuses the fiber node and just updates the necessary properties using data from a corresponding React element. React may also need to move the node in the hierarchy based on the key prop or delete it if the corresponding React element is no longer returned from the render method.

Check out the ChildReconciler function to see the list of all activities and corresponding functions React performs for existing fiber nodes.

Because React creates a fiber for each React element and since we have a tree of those elements, we’re going to have a tree of fiber nodes. In the case of our sample application it looks like this:

All fiber nodes are connected through a linked list using the following properties on fiber nodes: child , sibling and return . For more details on why it works this way, check out my article The how and why on React’s usage of linked list in Fiber if you haven’t read it already.

Current and work in progress trees

After the first render, React ends up with a fiber tree that reflects the state of the application that was used to render the UI. This tree is often referred to as current. When React starts working on updates it builds a so-called workInProgress tree that reflects the future state to be flushed to the screen.

All work is performed on fibers from the workInProgress tree. As React goes through the current tree, for each existing fiber node it creates an alternate node that constitutes the workInProgress tree. This node is created using the data from React elements returned by the render method. Once the updates are processed and all related work is completed, React will have an alternate tree ready to be flushed to the screen. Once this workInProgress tree is rendered on the screen, it becomes the current tree.

One of React’s core principles is consistency. React always updates the DOM in one go — it doesn’t show partial results. The workInProgress tree serves as a “draft” that’s not visible to the user, so that React can process all components first, and then flush their changes to the screen.

In the sources you’ll see a lot of functions that take fiber nodes from both the current and workInProgress trees. Here’s the signature of one such function:

Each fiber node holds a reference to its counterpart from the other tree in the alternate field. A node from the current tree points to the node from the workInProgress tree and vice versa.

Side-effects

We can think of a component in React as a function that uses the state and props to compute the UI representation. Every other activity like mutating the DOM or calling lifecycle methods should be considered a side-effect or, simply, an effect. Effects are also mentioned in the docs:

You’ve likely performed data fetching, subscriptions, or manually changing the DOM from React components before. We call these operations “side effects” (or “effects” for short) because they can affect other components and can’t be done during rendering.

You can see how most state and props updates will lead to side-effects. And since applying effects is a type of work, a fiber node is a convenient mechanism to track effects in addition to updates. Each fiber node can have effects associated with it. They are encoded in the effectTag field.

So effects in Fiber basically define the work that needs to be done for instances after updates have been processed. For host components (DOM elements) the work consists of adding, updating or removing elements. For class components React may need to update refs and call the componentDidMount and componentDidUpdate lifecycle methods. There are also other effects corresponding to other types of fibers.

Effects list

React processes updates very quickly and to achieve that level of performance it employs a few interesting techniques. One of them is building a linear list of fiber nodes with effects for quick iteration. Iterating the linear list is much faster than a tree, and there’s no need to spend time on nodes without side-effects.

The goal of this list is to mark nodes that have DOM updates or other effects associated with them. This list is a subset of the finishedWork tree and is linked using the nextEffect property instead of the child property used in the current and workInProgress trees.

Dan Abramov offered an analogy for an effects list. He likes to think of it as a Christmas tree, with “Christmas lights” binding all effectful nodes together. To visualize this, let’s imagine the following tree of fiber nodes where the highlighted nodes have some work to do. For example, our update caused c2 to be inserted into the DOM, d2 and c1 to change attributes, and b2 to fire a lifecycle method. The effect list will link them together so React can skip other nodes later:

You can see how the nodes with effects are linked together. When going over the nodes, React uses the firstEffect pointer to figure out where the list starts. So the diagram above can be represented as a linear list like this:

As you can see, React applies effects in the order from children and up to parents.

Root of the fiber tree

Every React application has one or more DOM elements that act as containers. In our case it’s the div element with the ID container .

React creates a fiber root object for each of those containers. You can access it using the reference to the DOM element:

This fiber root is where React holds the reference to a fiber tree. It is stored in the current property of the fiber root:

The fiber tree starts with a special type of fiber node which is HostRoot . It’s created internally and acts as a parent for your topmost component. There’s a link from the HostRoot fiber node back to the FiberRoot through the stateNode property:

You can explore the fiber tree by accessing the topmost HostRoot fiber node through the fiber root. Or you can get an individual fiber node from a component instance like this:

Fiber node structure

Let’s now take a look at the structure of fiber nodes created for the ClickCounter component

and the span DOM element:

There’s quite a lot of fields on fiber nodes. I’ve described the purpose of the fields alternate , effectTag and nextEffect in previous sections. Let’s now see why we need others.

stateNode

Holds the reference to the class instance of a component, a DOM node or other React element type associated with the fiber node. In general, we can say that this property is used to hold the local state associated with a fiber.

type

Defines the function or class associated with this fiber. For class components, it points to the constructor function and for DOM elements it specifies the HTML tag. I use this field quite often to understand what element a fiber node is related to.

tag

Defines the type of the fiber. It’s used in the reconciliation algorithm to determine what work needs to be done. As mentioned earlier, the work varies depending on the type of React element. The function createFiberFromTypeAndProps maps a React element to the corresponding fiber node type. In our application, the property tag for the ClickCounter component is 1 which denotes a ClassComponent and for the span element it’s 5 denoting a HostComponent .

updateQueue

A queue of state updates, callbacks and DOM updates.

memoizedState

State of the fiber that was used to create the output. When processing updates it reflects the state that’s currently rendered on the screen.

memoizedProps

Props of the fiber that were used to create the output during the previous render.

pendingProps

Props that have been updated from new data in React elements and need to be applied to child components or DOM elements.

key

Unique identifier with a group of children to help React figure out which items have changed, have been added or removed from the list. It’s related to the “lists and keys” functionality of React described here.