Photo credit: unsplash.com/photos/LG8T…
React Design Concept
According to the React website:
React is the preferred way to build large, responsive Web applications in JavaScript. It does well on Facebook and Instagram.
We know that the current refresh rate of mainstream browsers is 60Hz, that is every (1000ms / 60Hz) 16.6ms browser refresh. In this 16.6ms, do the following:
- First JS script execution;
- RequestAnimationFrame (rAF), that is, before each drawing, the rAF callback is performed;
- Layout operation, including calculation and update Layout;
- “Paint” is used to get the size and location of each node in the tree, and the browser fills in the content for each element.
- The next phase is Idle Peroid and can be executed at this time
requestIdleCallback
Tasks registered in;
If we don’t finish within 16.6ms, the page will lag to some extent.
The React v15 architecture
React 15 architecture is divided into two layers:
Reconciler
(coordinator) : Responsible for identifying changing components;Renderer
(renderer) : responsible for rendering the changed components to the page;
The Reconciler
The React API can trigger updates via this.setState, this.forceUpdate, reactdom.render, etc.
When an update occurs, the Reconciler does the following:
- Call the function component, or the class component’s render method, will return
JSX
intoVirtual DOM
; - will
Virtual DOM
Compared with the virtual DOM in the last update; - Find out the virtual DOM changed in this update through comparison;
- notice
Renderer
(renderer) render the changed virtual DOM to the page;
Renderer
React is cross-platform, with different renderers for different platforms. The Renderer for the browser is the ReactDOM library. In addition, there are renderers for other platforms:
- ReactNative: Render App native components;
- ReactTest: Renders pure JS objects for testing;
- ReactArt: Render to Canvas, SVG or VML (IE8);
Disadvantages of the React 15 architecture
In React 15, the Reconciler is called the stack Reconciler, which calls mountComponent when it is mounted, and updateComponent when it is updated. Both methods use recursive update subcomponents, fail to implement asynchronous interruptible updates, and schedule priorities. If the hierarchy of the component tree is very deep, recursion will take up a lot of thread time, resulting in a long JS execution time, more than 16.6ms (mainstream browser refresh rate is 60Hz, that is, every (1000ms / 60Hz)), easy to cause page lag.
The React 16 architecture
React 16 architecture can be divided into three layers:
Scheduler
— for scheduling taskspriority
, high-priority tasks are given priority in the Reconciler;The Reconciler
— Responsible for identifying changing components;Renderer
— Responsible for rendering the changed components to the page;
Scheduler
We know that some browsers already implement requestIdleCallback and notify us when the browser has time left. However, React has been abandoned due to the following factors:
- Browser compatibility;
- Trigger frequency is unstable;
For these reasons, the React team implemented its own polyfill for requestIdleCallback, known as Scheduler. In addition to the ability to trigger callbacks when idle, the Scheduler provides multiple scheduling priorities for tasks to set.
The Reconciler
The file is located at: github.com/facebook/re…
From React15 to React16, the Reconciler reconstructs with one goal in mind: to change the old architecture of synchronous updates to asynchronous interruptible updates. Updates may be interrupted in the middle of execution (browser shards run out of time or higher-priority tasks jump the queue) and revert to the intermediate state of the previous execution when it is possible to continue. Ceding CPU execution at the right time allows the browser to respond to user interactions in a timely manner.
Generator
Why didn’t the React team use Generator for asynchronous interruptibility? React team member sebmarkbage contributed answers in the 2016 issue Fiber Principles: Contributing To Fiber. The main reasons for giving up are as follows:
- The Generator is contagious, and other functions in the context need to be changed when it is used.
- Generators are stateful and cannot be recovered mid-stream.
Fiber reconciler
The “Fiber” Reconciler is a new attempt to address the problems inherent in the Stack Reconciler, while at the same time addressing some issues left over from history. Fiber became the default Reconciler starting with React 16.
Fiber has three meanings:
- As an architecture, before
React15
的Reconciler
The recursive method of execution, data stored in the recursive call stack, so calledstack Reconciler
. The React16Reconciler
Based on Fiber node, is calledFiber Reconciler
. - As a
Static data structures
For example, there is one for each Fiber nodeReact element
, the use ofThe list
The implementation. Saves the type of the component, the corresponding DOM node and other information. - As a
Dynamic units of work
For example, each Fiber node holds the component’s changed state, work to be performed (need to be deleted/inserted/updated…) during this update. .
The main objectives of Fiber are:
- Be able to slice interruptible tasks.
- Ability to reprioritize, reset, and reuse tasks.
- Ability to interleave parent and child elements to support layout in React.
- Ability to return multiple elements in render().
- Better support for error boundaries.
The Fiber structure
The Fiber structure is defined in the React source code, as shown below.
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Properties as static data structures
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// Connect other Fiber nodes to form a Fiber tree
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
// As a dynamic unit of work attribute
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
// Effects
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
// Scheduling priority is related
this.lanes = NoLanes;
this.childLanes = NoLanes;
// Point to the corresponding fiber from the next update
this.alternate = null;
}
Copy the code
As an architecture
// Point to the parent Fiber node
this.return = null;
// Point to the subfiber node
this.child = null;
// Point to the first sibling Fiber node on the right
this.sibling = null;
Copy the code
For example, here’s an example:
function App() {
return (
<div>
<span> Hello </span>
<span> World </span>
</div>)}Copy the code
Corresponding Fiber tree structure:
As a static data structure
Function/Class/Host...
this.tag = tag;
/ / the key attribute
this.key = key;
// In most cases, the same as type. In some cases, FunctionComponent uses the React. Memo package
this.elementType = null;
// For FunctionComponent, it refers to the function itself; for ClassComponent, it refers to the class; for HostComponent, it refers to the DOM node tagName
this.type = null;
// The actual DOM node corresponding to Fiber
this.stateNode = null;
Copy the code
As a dynamic unit of work
As a dynamic unit of work, the following parameters in Fiber hold information related to this update.
// Save the status changes caused by this update
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
// Save the DOM operation caused by this update
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
Copy the code
Fiber Dual cache tree
There are at most two Fiber trees in React. The Fiber tree corresponding to the content currently displayed on the screen is called the Current Fiber tree, and the Fiber tree being built in memory is called the workInProgress Fiber tree.
The Fiber node in the current Fiber tree is called current Fiber, and the Fiber node in the workInProgress Fiber tree is called workInProgress Fiber. They connect via the Alternate property.
currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;
Copy the code
The React root node switches the current Fiber tree orientation by switching the current pointer between rootfibers in different Fiber trees.
When the workInProgress Fiber tree is built and given to the Renderer to render on the page, apply the current pointer of the root node to the workInProgress Fiber tree. The workInProgress Fiber tree becomes the current Fiber tree.
Each status update generates a new workInProgress Fiber tree, and DOM updates are completed by replacing current with workInProgress. Look at the following example:
1. The componentsmount
时
import React from "react";
import ReactDOM from "react-dom";
function App() {
const [num, addNum] = React.useState(0);
return <div onClick={()= > addNum(num + 1)}>{num}</div>;
}
ReactDOM.render(<App />.document.getElementById("root"));
Copy the code
- For the first time to perform
ReactDOM.render
Will createfiberRootNode
和rootFiber
. The fiberRootNode isThe root node of the entire application
, rootFiber is whereThe root node of the component tree
. The reason for distinguishing fiberRootNode from rootFiber is that in our application we can call ReactDOM. Render multiple times to render different component trees, which will have different Rootfibers. butThere is only one root node for the entire application
, that is,fiberRootNode
. The fiberRootNode’s Current pointer points to the Fiber tree for the rendered content on the current page, the Current Fiber tree.
Fiberrootnode. current points to a rootFiber that does not have any sub-fiber nodes, so the current Fiber tree is empty.
- Let’s go into
render
Phase, according to the component returnedJSX
Fiber nodes are created in order in memory and connected together to build a Fiber tree, calledworkInProgress Fiber
The tree. When building the workInProgress Fiber tree, it will try to reuse the attributes in the existing Fiber nodes in the current Fiber tree, and only the corresponding current Fiber exists in the first screen rendering.
- The completed workInProgress Fiber tree is in
commit
Phase rendering to the page.
2. The componentupdate
时
- When we click
div
The node triggers a state change and starts a new onerender
Stage and build a new treeworkInProgress Fiber
The tree.
workInProgress Fiber
The trees inrender
Enter after the phase completes the buildcommit
Phase rendering to the page. After rendering, the workInProgress Fiber tree becomes the current Fiber tree.
The resources
- React Technology revealed
- Step into the world of React Fiber
- React Fiber source code parsing