React is a rich JavaScript framework. I think it's necessary to know a high-level internal working of a language or a framework to use it effectively. React's performance comes from its internal data structures and algorithms. In this article, I will not touch upon the actual codebase, data structures, or algorithms. I will share, on a high level, how React 16 renders and updates the UI. So, let's get started!
Smart data structures and dumb code works a lot better than the other way around. - Eric S. Raymond
Internal Representation of Components
During parsing, React creates an in-memory representation of components for easy rendering and updating. Typical React components can have multiple children and sibling components. We have multiple options to represent a component.
- N-ary tree.
- Multi-linked doubly linked list.
Sample Component
Representation of The Component
The following diagram shows the internal representation for the above component using both data structures.
For both the data structures,
- we can represent the parent-child relationship vertically.
- we can represent sibling relationships horizontally.
- all the relationships are bidirectional for easy traversal.
One thing to note - I am taking a component for simplicity. I am not taking the entire page into the scope.
Rendering and Updating React Component
There can be two types of rendering - simple rendering without any updates or rendering page components after updates in a dynamic UI. Let's see how each scenario works.
Simple Rendering without Updates
In this case, React can use a combination of Depth-First and Breadth-First Traversal to render the entire component (for both types of representation).
Handling UI Changes
In a dynamic user interface, we will have periodic updates as well as other high-priority activities like network calls. It is possible while rendering current changes, some other high-priority tasks come up. In that case, React may have to do a context switch. And that's where React shines. How does React handle that? Let's jump into that.
[I will use representation and DS (for data structure) inter-changeably.]
Rendering Phase
Let's call the original representation current copy. Let's go step by step.
- Engine starts cloning the current copy into another DS by traversal. Let's call it work-in-progress copy.
- If there is any change in any Node, it can tag the updated Node during traversal. It can store the updates in a separate internal DS like a list. Let's call it effects list.
Let's assume, for our example, Logo, About Us, and Products sub-components have changed after this operation. In that case, the following can be the effects list.
Why not update the UI while traversal?
Let's suppose, the user creates an animation with tasks A and B. React is supposed to render A and B consecutively for creating a rich experience. Now, a high-priority task has arrived between A and B. Engine cannot ignore it. If the engine has to perform it between A and B by stopping B, the user will see a glitch between A and B. It is not desired user experience.
Why collect updates in a separate DS?
As a high-priority task may arrive in between, rendering may not be as important as that task. In that case, React should switch context. After finishing that task, it can resume the traversal again. This collection of updates will help React to start the operation easily again.
Commit Phase
After the collection of updates in a DS, it's time for applying the changes. It has to go in one shot. Otherwise, the user will see glitches and partial updates.
- We can traverse the effects list and apply the updates in the actual UI. It has to be synchronous operation.
- Once everything is done, React needs to store the updated DS in current copy to represent the current UI. How to do that? Yes, you guessed it right - point current copy to work-in-progress copy.
The above steps complete the entire update cycle. React engine applies various optimizations. We will explore React internals in detail in the next post. I promise I will touch on React data structures and codebase.
Notes
- React uses the Multi-Linked Doubly Linked List representation internally.
- I have used nomenclature used by React teams like current copy, work-in-progress copy, and effects list. Naming is always harder. They did a good job with these names. So, I just used the names.
- In React 15, React used to perform partial updates as I mentioned in Why not update the UI while traversal? section. In React 16, they have changed the algorithm.
- Using an effects list kind of DS in compiler is quite interesting. It is worth a separate post. I have seen this pattern to execute a bunch of assembly code for showing the final updates to the user for low-level language compilation. It is a great example of the power of simple data structures like Linked List. Let me know if you want to know more about this technique in the comments. I will try to create a post on that particularly.
- Check out my article about React Virtual DOM.
If you enjoyed the article, please don't forget to like it. In case you have any doubts, ask in the comment section.
Happy Learning! ๐
Top comments (0)