This story is part of a series where we write our own version of React, but since we are going to rewrite most of the old code anyway, I’ll tl;dr it for you:

TL;DR of the series so far: We are writing a React clone to understand what React does under the hood. We call it Didact. To keep our code simple we focus only on React main features. First we covered how to render elements and make JSX work. We wrote the reconciliation algorithm to re-render only the stuff that changed between updates. And then we added class components and setState() .

Now React 16 is out, and with it a new internal architecture that required a rewrite of most of React’s code.

This means that some long-awaited features — that were hard to develop with the old architecture — were shipped.

It also means that most of the code we have written on this series is now worthless 😛.

In this post we are going to rewrite most of the code from the didact series to follow React 16 new architecture. We’ll try to mirror the structure, variables and function names from the React codebase. We’ll skip everything we don’t need for our public API:

Didact.createElement()

Didact.render() (only DOM rendering)

(only DOM rendering) Didact.Component (with setState() but not context or life cycle methods)

If you want to jump ahead and see the code working you can go to the updated demo or visit the github repository.

Let me explain why we need to rewrite the old code.

Why Fiber

This won’t offer the full picture of React Fiber. If you want to know more about it, please check this list of resources.

When the browser’s main thread is kept busy running something for a long time, critical brief tasks have to wait an unacceptable amount of time to get done.

To showcase this problem I made a little demo. In order to keep the planets spinning, the main thread needs to be available for an instant every 16ms or so. If the main thread is blocked doing other stuff for, let’s say 200 ms, you’ll notice the animation missing frames and the planets frozen until the main thread is free again.

What makes the main thread so busy that can’t spare some microseconds on keeping the animation smooth and the UI responsive?

Remember the reconciliation code? Once it starts reconciling it doesn’t stop. If the main thread needs to do anything else it will have to wait. And, because it depends a lot on recursive calls, it’s hard to make it pausable. That’s why we are going to rewrite it using a new data structure that will allow us to replace the recursive calls with loops.

The truth is that I wrote this article so more people could get the joke

Scheduling micro-tasks

We’ll need to split up the work into smaller pieces, run those pieces for a short period of time, let the main thread do higher priority stuff, and come back to finish the work if there’s anything pending.

We’ll do this with the help of requestIdleCallback() function. It queues a callback to be called the next time the browser is idle and includes a deadline parameter describing how much time available we have for our code:

The real work happens inside the performUnitOfWork function. We need to write our reconciliation code there. The function should run a piece of the work and then returns all the information it needs to resume the work the next time.

To track those pieces of work we will use fibers.

The fiber data structure

We will create a fiber for each component we want to render. The nextUnitOfWork will be a reference to the next fiber we want to work on. performUnitOfWork will work on that fiber and return a new one until all the work is finished. Bear with me, I’ll explain this in detail later.

How does a fiber look like?

It’s a plain old JavaScript object.

We’ll use the parent , child , and sibling properties to build a tree of fibers that describes the tree of components.

The stateNode will be the reference to the component instance. It could be either a DOM element or an instance of a user defined class component.

For example:

In the example we can see the three different kind of components we will support:

The fibers for b , p , and i represent host components . We will identify them with the tag HOST_COMPONENT . The type for these fibers will be a string (the tag of the html element). The props will be the attributes and event listeners of the element.

, , and represent . We will identify them with the . The for these fibers will be a string (the tag of the html element). The will be the attributes and event listeners of the element. The Foo fiber represents a class component . Its tag will be CLASS_COMPONENT and the type a reference to the user defined class extending Didact.Component .

fiber represents a . Its will be and the a reference to the user defined class extending . The fiber for div represents the host root. It’s similar to a host component because it has a DOM element as the stateNode but being the root of the tree it will receive special treatment. The tag for this fiber will be HOST_ROOT . Note that the stateNode of this fiber is the DOM node passed to Didact.render() .

Another important property is alternate . We need it because most of the time we will have two fiber trees. One tree will correspond to the things we’ve already rendered to the DOM, we’ll call it the current tree or the old tree. The other is the tree we build when we work on a new update (a call to setState() or Didact.render() ), we’ll call this tree the work-in-progress tree.

The work-in-progress tree won’t share any fiber with the old tree. Once we finished building the work-in-progress tree and made the needed DOM mutations, the work-in-progress tree becomes the old tree.

So we use alternate to link the work-in-progress fibers with their corresponding fibers from the old tree. A fiber and its alternate share the same tag , type and stateNode . Sometimes — when we are rendering new stuff — fibers won’t have an alternate .

Finally, we have the effects list and effectTag . When we find a fiber in the work-in-progress tree that requires a change to the DOM we will set the effectTag to PLACEMENT , UPDATE or DELETION . To make it easier to commit all the DOM mutations together we keep a list of all the fibers (from the fiber sub-tree) that have an effectTag listed in effects .

That was probably too much information at once, don’t worry if you didn’t follow, we’ll see the fiber trees in action very soon.

Didact call hierarchy

To get an idea of the flow of the code we are going to write take a look at this diagram:

We’ll start from render() and setState() and follow the flow ending at commitAllWork() .

Old code

I told you that we are going to rewrite most of the code, but let’s first review the code that we are not rewriting.

In Element creation and JSX we wrote the code for createElement() , the function used by transpiled JSX. We don’t need to change it, we’ll keep using the same elements. If you don’t know about elements, type , props and children , please review the old post.

In Instances, reconciliation and virtual DOM we wrote updateDomProperties() for updating the DOM properties of a node. I also extracted the code for creating DOM elements to createDomElement() . You can see both functions in this dom-utils.js gist.

In Components and state we wrote the Component base class. Let’s change it so setState() calls scheduleUpdate() , and createInstance() saves a reference to the fiber on the instance:

Starting with this code and nothing else let’s rewrite the rest from scratch.