DEV Community

chioma
chioma

Posted on

How rendering works: The commit phase

Day 29 of 100days of code❤

A quick recap of the render phase:

The end result of the reconciliation process is an updated fiber tree and a list of DOM updates that need to be performed in the next phase. React has still not written anything to the DOM yet but has figured out the list of effects. This is the final result of the render phase, which includes the DOM operations that will be made in the commit phase.

How rendering works: The commit phase

The commit phase and Browser paint.

The commit phase:

In the commit phase, React finally writes to the DOM. This phase involves executing the list of DOM updates, which includes insertions, deletions, and updates of DOM elements. React flushes these updates to the DOM, applying them one by one to the actual DOM elements that already exist in the DOM tree. Unlike the render phase, committing is synchronous, meaning it occurs in one go without interruption. This ensures that the DOM never displays partial results, maintaining a consistent UI that remains in sync with the application state at all times.
Once the commit phase concludes, the work-in-progress fiber tree transitions to become the current tree for the subsequent render cycle.

Browser paint:

After changes are detected in the DOM, the browser repaints the screen to reflect the updated UI. This process is handled internally by the browser and is independent of React.
While the render phase is managed by React, the commit phase involves a separate library called ReactDOM, which is responsible for writing to the DOM. This is why we import both React and ReactDOM.

It's important to note that React itself doesn't directly manipulate the DOM; its primary function is to render components. React doesn't determine where the render result will be applied.
React was intentionally designed to be platform-agnostic, allowing it to be used across various platforms or hosts. For example, React Native enables building native mobile applications for iOS and Android using React components. This showcases React's versatility and its ability to adapt to different environments.

Putting it all together:

The process of rendering and displaying a React application on the screen begins with a trigger, such as the initial render or a state update. This trigger initiates the render phase, during which no visual output is produced. In this phase, all component instances requiring a re-render are rendered, meaning their respective component functions are called. This results in the creation of updated React elements, which are placed in a new virtual DOM - a tree structure of React elements.

It's important to note that rendering a component also renders all of its child components, regardless of whether their props have changed or not. This is because React cannot determine if the children were affected by the parent rendering.

The newly created virtual DOM needs to be reconciled with the current fiber tree before the state update can occur. This reconciliation process is essential to avoid the inefficiency of destroying and rebuilding the entire DOM tree with every update. Reconciliation aims to reuse as much of the DOM as possible by identifying the smallest number of DOM updates needed to reflect the latest state update.

The reconciliation process is facilitated by a reconciler called the Fiber, which operates with a mutable data structure known as the fiber tree. Each React element and DOM element in the fiber tree is associated with a fiber that holds the actual component state, props, and a queue of work.
After reconciliation, the queue of work contains the necessary DOM updates for the element.
The computation of DOM updates is performed by an algorithm called the diffing algorithm, which systematically compares elements in the new virtual DOM with elements in the current fiber tree to identify changes. The result of the reconciliation and diffing process is an updated fiber tree and a list of all the necessary DOM updates.

Note: The render phase in React is asynchronous, allowing fibers to split, prioritize, pause, and resume work. This asynchronous behavior is crucial in preventing the JavaScript engine from being blocked by complex rendering processes.
In the commit phase, the list of DOM updates generated during the render phase is applied to the DOM. This phase is handled by a renderer like ReactDOM, which performs operations such as editing, deleting, and updating DOM elements to reflect the new state of the application.
Unlike the render phase, the commit phase is synchronous. This means that all DOM updates are executed in one go, ensuring a consistent UI over time.

Finally, once the browser detects that the DOM has been updated, it initiates a new browser paint to visually update the user interface on the screen. This completes the process of rendering and displaying the React application.

Diffing

Diffing in React is based on two fundamental assumptions:

  1. Elements of different types will produce different trees.

  2. Elements with a stable key will stay the same across renders.

These assumptions enable the diffing algorithm to be significantly faster, reducing the number of operations required from potentially billions to just thousands.

Diffing involves comparing elements step-by-step between two renders based on their positions in the tree.
There are two primary situations to consider:

  1. When two different elements are found at the same position in the tree between two renders.

  2. When the same element is found at the same position in the tree between two renders.

In the first situation, if an element changes type (e.g., from a

to a ), React assumes that the element and all its children are no longer valid. Therefore, they are destroyed and removed from the DOM. This includes their state. The tree is rebuilt with brand new elements, meaning any components with state will have their state effectively reset.
In the second situation, if the same element is found at the same position in the tree between two renders, it will simply be kept in the DOM. This includes all child elements and preserves the component's state.

React efficiently updates the DOM by mutating element attributes or passing in new props for React elements, rather than removing and recreating elements unnecessarily. However, sometimes it may be desirable to create a brand new component instance with new state instead of preserving the existing state.

Thank you for reading.❤💪

Top comments (0)