How React works
This is day 28 of my 100 Days of code challenge.
And let’s start with just a tiny recap👇👇
When we create an application, what we are really doing is building a collection of components. Component instances are created when we use components in our application. These component instances are the actual physical components that exist in our application and hold state and props. As React calls each component instance, JSX will produce a series of React.createElement function calls, which in turn will create a React element for each component instance. These React elements are then transformed into DOM elements and displayed as the user interface on the screen.
How components are displayed on the screen
This process begins when a render is triggered. By updating state somewhere, a render is triggered, and the next phase is the render phase. In the render phase, React calls component functions and determines how the DOM should be updated to reflect the latest state change.
Note: The DOM is not updated in the render phase, unlike what we usually understand as rendering. React's definition of rendering is different, which can be confusing. In React, rendering does not directly update the DOM or display elements on the screen. Rendering happens internally inside React and does not produce any visual changes.
After the render phase comes the commit phase, where React actually writes to the DOM by updating, inserting, and deleting elements.
Note: The render and commit phases combined are what we traditionally call rendering. Finally, the browser notices that the DOM has been updated, and it repaints the screen. The browser repaint is what produces the visual change.
How renders are triggered
There are two situations that trigger render:
The first is the very first time the application runs, which is the initial render of the application.
Then, a state update in one or more component instances triggers a re-render.
Note: It is important to note that the render process is triggered for the entire application, not just for one single component. However, this doesn't mean that the entire DOM is updated. In React, rendering involves calling the component function and figuring out what needs to change. In practice, it may appear that React only re-renders the component where the state update happens, but behind the scenes, React determines the minimal set of changes needed to update the DOM efficiently.
Also, note that renders are not triggered immediately when a state update happens but are scheduled for when the JavaScript engine has some free time. This scheduling typically occurs within a few milliseconds, so it's not noticeable to the user.
How rendering works:The render phase
At the beginning of the render phase, React goes through the entire component tree and takes all the component instances that triggered a re-render, then renders them by calling the corresponding component function.
This process generates updated React elements, which together make up the virtual DOM.
During the initial render, React takes the component tree and transforms it into one large React element tree. This is what we refer to as the virtual DOM.
Virtual DOM
The virtual DOM is indeed a tree of all React elements created from all instances in the component tree. It's important to note that the virtual DOM is separate from the Shadow DOM, which is a separate concept used by web components.
Consider the component tree above. When updating the state in component N, it triggers a re-render, causing React to call the function of component N and place the new React element in a new React element tree, which is the virtual DOM.
Rendering a component also causes all of its child components to be re-rendered, regardless of whether their props have changed or not. So, if a state update happens in component M, components H, I, J, K, and L will also be re-rendered. Similarly, if we update the highest component, which is component O, then the entire application will be re-rendered. React employs this strategy because it doesn't know in advance whether children will be affected by the state change.
Note: This does not mean that the entire DOM is updated; rather, a new virtual DOM is recreated.
The new virtual DOM created will be reconciled with the current Fiber tree as it exists before the state is updated. This reconciliation process is performed in React's reconciler, which is called Fiber. The result of the reconciliation process is an updated Fiber tree(work in progress tree), which will then be used to write to the DOM.
what is reconciliation and why do we need it
The reason why React doesn't update the DOM whenever state changes somewhere in the app directly is because creating a virtual DOM is cheap and fast, as it's just a JavaScript object. On the other hand, writing to the actual DOM is relatively slow and would be inefficient and wasteful to do each time the render is triggered.
Usually, when state changes somewhere in the app, only a small part of the DOM needs to be updated, and the rest of the DOM can be reused.
To achieve efficiency, whenever a render is triggered, React tries to use as much of the existing DOM as possible. It does this through a process called reconciliation. Reconciliation involves deciding which DOM elements actually need to be inserted, deleted, or updated in order to reflect the latest state change. The result of reconciliation is a list of DOM operations necessary to update the current DOM with the new state.
Reconciliation is processed by a reconciler, which is the engine or heart of React. This is what allows React to never directly touch the DOM and instead tell React what the next snapshot of the UI should look like based on the state.
The Reconciler : Fiber
During the initial render of the component, Fiber takes the entire virtual DOM and builds another tree known as the Fiber tree. The Fiber tree is a special internal tree that contains a Fiber node for each component instance and DOM element.
Unlike React elements in the virtual DOM, the Fibers are not recreated on every render. Instead, the Fiber tree is never destroyed; But once created during the initial render, it is mutated over and over again in future reconciliation steps. This makes Fiber the perfect place for keeping track of things like the current component state, props, side effects, and a list of used hooks. The actual state and props of any component instance are internally stored inside the corresponding Fiber in the Fiber tree.
Fiber is also defined as the unit of work. Unlike the normal React element tree, Fiber nodes are structured in a linked list manner. The first child has a link to the parent, and all the other children have links to their previous siblings. This structure is known as a linked list, making it easier for React to process the work associated with each Fiber.
One characteristic of the Fiber reconciler is that work can be done asynchronously. This means that the rendering process, which is what the reconciler does, can be split into chunks. Tasks can be prioritized, and work can be paused, reused, or thrown away as needed. This allows for more efficient and responsive rendering in React application.
Top comments (0)