React Fiber explained
Facebook began the creation of React Fiber in 2015(It is currently the default reconciler). The main task was to invent an algorithm that would reduce the consumption of system resources to accelerate the application performance and increase the responsiveness of the UI(user interface) with decreased user device loads. Let’s understand how React Fiber makes this possible.
You will learn the following in this article:
- What are the core components that React uses to render the UI
- What is the Fiber Reconciliation algorithm
- The advantages of Fiber and how it improves your React app
- What the
fiber
object is and its importance - How the Fiber algorithm works and its usage
Reconciler, Renderer, And Scheduling
To understand React Fiber, we need to know what the reconciler and renderer are. These are the two core components used by React to render our applications.
-
Reconciler All the changes that need to be applied to the current tree of React Elements to reflect the updated state on the UI are determined by the reconciler during reconciliation.
-
Renderer Once your tree is ready, you need to apply these changes on the UI; renderer does that for you. An example is the React DOM which updates the DOM in browsers and React Native for native iOS and Android views. This separation means that React DOM and React Native can use their renderers while sharing the same reconciler, provided by React core.
-
Scheduling Scheduling simply determines when work should be performed. By work we mean any computations that must be performed. Work is usually the result of an update (e.g., state change, lifecycle function, or changes in the DOM).
As per React Design Principles document:
Even when your components are described as functions when you use React you don’t call them directly. Every component returns a description of what needs to be rendered, and that description may include both user-written components like
<LikeButton>
and platform-specific components like<div>
. It is up to React to “unroll”<LikeButton>
at some point in the future and actually apply changes to the UI tree according to the render results of the components recursively.
This is a subtle distinction but a powerful one. Since you don’t call that component function but let React call it, it means React has the power to delay calling it if necessary. In its current implementation React walks the tree recursively and calls render functions of the whole updated tree during a single tick. However in the future it might start delaying some updates to avoid dropping frames.
This is a common theme in React design. Some popular libraries implement the “push” approach where computations are performed when the new data is available. React, however, sticks to the “pull” approach where computations can be delayed until necessary.
The main points are:
- In a UI, it’s not required for every update to be applied immediately; in fact, doing so can be wasteful, causing frames to drop and degrading the user experience.
- Different types of updates have different priorities — an animation update needs to complete more quickly than an update from a data store (e.g., an API request).
- A push-based approach requires the app (you, the programmer) to decide how to schedule work. A pull-based approach allows the framework (React) to be smart and make those decisions for you.
React Fiber
In a nutshell, React Fiber is simply a reimplementation of React’s core reconciliation algorithm. It can be said to be the reimplementation of the stack but specialized for react components(where the stack can be interrupted at will and stack frames manipulated manually). It has been the default reconciler since React 16.
The primary goal of the React Fiber reconciliation algorithm is to enable React to take advantage of scheduling(which was not possible with the previous stack reconciler). React is now able to:
- pause work and come back to it later.
- split work into chunks and prioritize tasks
- reuse previously completed work.
- abort work if it’s no longer needed.
As a result, there is an overall improvement in the responsiveness of the UI and overall performance of React applications, especially apps with animations.
An animation implemented with the Stack reconciler vs. Fiber reconciler—as you can see, the animation is smoother when implemented with Fiber. View Demo*
Session Replay for Developers
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — an open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.
Fiber
For React Fiber to do any of the things listed in the preceding section, it first needs a way to break work down into units. In a sense, that’s what a fiber (not Fiber with capital ‘F’) is. A fiber represents a unit of work.
Since React Fiber is the reimplementation of the stack (a more customizable stack), we can think of a single fiber as a virtual stack frame. It corresponds to a stack frame but maintains a one-to-one relationship with the instances of react components.
The literal implementation of a fiber is an object. It is simply a Javascript object that contains information about a react component.
The first fiber node created by React is the host root, which represents the container DOM node ( the DOM element which you pass to ReactDOM.render()
but as of React 18 root.render()
)
A fiber object has specific properties that allow it to track information and the relationship between fiber nodes.
fiberNode{
stateNode,
child,
sibling,
return,
type,
alternate,
key,
updateQueue,
memoizedState,
pendingProps,
memoizedProps,
tag,
effectTag,
nextEffect
}
stateNode
refers to the component instance a fiber belongs to.child
andsibling
point to other fibers with respect to the current fiber node.
The child fiber corresponds to the value returned by a component’s render
method. So in the following example,
function Parent() {
return <Child />
}
The sibling field accounts for the case where render
returns multiple children.
function Parent() {
return [<Child1 />, <Child2 />]
}
-
return
: The return fiber is the fiber to which the program should return after processing the current one. It can be said to be parent fiber. If a fiber has multiple child fibers, each child fiber’s return fiber is the parent. So in our example in the previous section, the return fiber ofChild1
andChild2
isParent
. -
type
:The type of a fiber describes the component it corresponds to. It determines if it’s a class, function, or DOM element. -
key
:This is used during reconciliation to determine whether the fiber can be reused by identifying all the changed, added, or removed elements. -
alternate
flush To flush a fiber is to render its output onto the screen.
work-in-progress A fiber that has not yet been completed; conceptually, a stack frame that has not yet returned. At any time, a component instance has at most two fibers that correspond to it: the current, flushed fiber, and the work-in-progress fiber.
The alternate of the current fiber is work-in-progress, and the alternate of the work-in-progress is the current fiber.
A fiber’s alternate is created lazily using a function called cloneFiber
. Rather than always creating a new object, cloneFiber
will attempt to reuse the fiber’s alternate if it exists, minimizing allocations.
updateQueue
: This queues all the state & DOM updates or any other effect.memoizedState
: This refers to the state of the previous render.memoizedProps
andpendingProps
: Semantically, props are the arguments of a function. A fiber’spendingProps
are set at the beginning of its execution, andmemoizedProps
is set at the end. When the incomingpendingProps
are equal tomemoizedProps
, it signals that the fiber’s previous output can be reused, preventing unnecessary work.tag
: This specifies the type of fiber. Example: Class component, Function component, Host portal.effectTag
: This holds the information about the side-effect that must be applied.nextEffect
: This points to the next node in the effects list, which has an update.
N/B: It is important to note that React fibers are not similar to react elements. Though they are often created from react elements and even share some properties(type
and key
), the key difference between both is: while React elements are recreated every time, fibers are being reused as often as possible (though they have to be created at the initial render).
How React Fiber Works
Since a fiber presents a unit of work, before React renders anything to the DOM, it processes each fiber(unit of work) until we end up with something called ‘finished work’. React then commits this ‘finished work’ which results in visible changes in the DOM. This all happens in two phases.
Rendering a tree of fibers
There are two trees Fiber uses to render our UI, the current and workinProgress tree. The current tree is what is currently rendered on the UI(or Screen); React can’t make changes to this tree because it will result in an inconsistent UI. React instead makes changes to the workinProgress tree and swaps pointers once all changes are computed. The current tree then becomes the workinProgress tree, and the workinProgress tree becomes the current tree.
How does Fiber avoid UI inconsistency? By simply splitting work into two phases:
Render/Reconciliation Phase
In this phase, React starts building the workinProgress tree, which follows a process like this:
setState()
method is called to update a component’s state React knows it has to now schedule the work usingrequestIdleCallback()
, which lets the main thread know that it has to pick up the work once it has some free(Idle) time.- React now starts creating the workinProgress Fiber tree by cloning the elements from the current Fiber tree and goes through each node to determine if it has to be changed
- If a particular node has been updated, it is added to another list called an effects list, a linear linked list of all the changes that need to be made.
- Once the entire workinProgress tree is traversed, and all the updated nodes are tagged, the first phase is completed.
Commit Phase
In this phase, all the updates for the nodes in the effect list are performed and reflected on the DOM. The main thread applies all these changes in a single go. This phase is synchronous, unlike the render phase, which can be paused and resumed.
React Fiber Usage
Some features that you can currently use in React because of Fiber are:
-
Error boundaries—previously, when errors happen in the
render
method, it messes React up internally. But with error boundaries, we can prevent this from happening. This is done through thegetDerivedStateFromError()
andcomponentDidCatch()
methods. -
Code-splitting and Concurrency(thanks to react 18).
Conclusion
This article is a simple introduction to the React Fiber algorithm and a high-level view of how it works. There is a deeper level of abstraction to the algorithm, but you now know the fundamental concepts behind the Fiber Reconciler and how it works.
Additional Resources
- Watch Lin Clark - A Cartoon Intro to Fiber - React Conf 2017
- Watch Sebastian Markbåge - React Performance End to End (React Fiber)— React Conf 2017
- Read React-fiber-architecture— React Docs
A TIP FROM THE EDITOR: For more on Fiber-related topics, do not miss our React 18 - What’s New and How it Will Benefit Developers and Catching Errors In React With Error Boundaries articles.