Picture source unsplash.com/photos/LG8T...
React design philosophy
From the React official website, we can see this sentence:
React is built with JavaScript
Quick responseThe preferred way for large-scale web applications. It performs well on Facebook and Instagram.
We know that the current refresh frequency of mainstream browsers is
- 1. the JS script is executed;
- Execute requestAnimationFrame (rAF), that is, before each drawing, the rAF callback will be executed;
- Perform Layout operations, including calculating layout and updating layout;
- Perform the Paint operation to get information such as the size and position of each node in the tree, and the browser will fill in the content for each element;
- Next in the idle phase (Idle Peroid), can be executed at this time requestIdleCallbackTasks registered in
If we do not complete within 16.6ms, the page will appear to a certain extent
React v15 architecture
The React 15 architecture is divided into two layers:
- Reconciler(Coordinator): Responsible for finding the changed components;
- Renderer(Renderer): Responsible for rendering the changed components to the page;
Reconciler (Coordinator)
Can pass in React
When an update occurs, Reconciler will do the following:
- Call the render method of the function component or the class component, and it will return JSXConverted toVirtual DOM;
- willVirtual DOMCompare with the virtual DOM at the time of the last update;
- Find out the virtual DOM that has changed in this update by comparison;
- Notice Renderer(Renderer) Render the changed virtual DOM onto the page;
Renderer
React supports cross-platform, and different platforms have different Renderers. The browser's Renderer 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 React 15 architecture
In React 15 version Reconciler is called
React 16 architecture
The React 16 architecture can be divided into three layers:
- SchedulerScheduling taskspriority, High-priority tasks enter the Reconciler first;
- Reconciler (Coordinator)Responsible for finding the changed components;
- RendererResponsible for rendering the changed components to the page;
Scheduler
We know that some browsers have already implemented
- Browser compatibility;
- The trigger frequency is unstable;
Based on the above reasons, the React team implemented requestIdleCallback by itself
Reconciler (Coordinator)
The file is located at: github.com/facebook/re...
From
Generator
Why didn't the React team use Generator to achieve asynchronous interruptible? React team member
- Generator is contagious, and other functions of the context need to be changed if Generator is used.
- The generator is stateful and cannot be restored midway.
Fiber reconciler
- As an architecture, before React15ofReconcilerIt is executed in a recursive manner, and the data is stored in the recursive call stack, so it is calledstack Reconciler. React16ReconcilerBased on Fiber node implementation, known asFiber Reconciler.
- AsStatic data structureSay, each Fiber node corresponds to oneReact element,useLinked listachieve. The type of the component, the corresponding DOM node and other information are saved.
- AsDynamic unit of workIn other words, each Fiber node saves the changed state of the component in this update and the work to be performed (need to be deleted/inserted into the page/updated...).
The main goals of Fiber are:
- Ability to slice and process interruptible tasks.
- Ability to adjust priority, reset and reuse tasks.
- Ability to interleave between parent elements and child elements to support layout in React.
- Ability to return multiple elements in render().
- Better support for error boundaries.
Fiber structure
The definition of Fiber structure in React source code is as follows.
function FiberNode (
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
//As an attribute of static data structure
this .tag = tag;
this .key = key;
this .elementType = null ;
this .type = null ;
this .stateNode = null ;
//Used to 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 property of a dynamic unit of work
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 related
this .lanes = NoLanes;
this .childLanes = NoLanes;
//Point to the fiber corresponding to the fiber in another update
this .alternate = null ;
}
Copy code
As a framework
//Fiber parent node points to
the this .return = null ;
//points to child nodes Fiber
the this .child = null ;
//to point to the right of the first sibling node Fiber
the this .sibling = null ;
duplicated code
For example, like the following example:
function App () {
return (
< div >
< span > Hello </span >
< span > World </span >
</div >
)
}
Copy code
corresponding
As a static data structure
//Fiber corresponding component type Function/Class/Host...
this .tag = tag;
//key attribute
this .key = key;
//Most cases are the same type, some cases are different, for example, FunctionComponent uses React.memo Wrap
this .elementType = null ;
//For FunctionComponent, it refers to the function itself, for ClassComponent, it refers to class, and for HostComponent, it refers to the DOM node tagName
this .type = null ;
//The real DOM node corresponding to Fiber
this .stateNode = null ;
copy Code
As a dynamic unit of work
As a dynamic work unit, the following parameters in Fiber save the information related to this update.
//Save information about the state 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 code
Fiber double buffer tree
At most two Fiber trees can exist in React at the same time. The Fiber tree corresponding to the content displayed on the current screen is called
The Fiber node in the current Fiber tree is called
currentFiber.alternate === workInProgressFiber; workInProgressFiber.alternate === currentFiber; Copy code
The root node of the React application uses
when
Each state update will generate a new workInProgress Fiber tree, through the replacement of current and workInProgress, complete the DOM update. Look at the following example:
1. Components mount Time
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 code
- First execution ReactDOM.renderWill createfiberRootNodewithrootFiber. Where fiberRootNode isThe root node of the entire application, RootFiber is whereThe root node of the component tree. The reason why fiberRootNode and rootFiber are distinguished is that in the application we can call ReactDOM.render multiple times to render different component trees, and they will have different rootFiber. butThere is only one root node for the entire application,That isfiberRootNode. The current pointer of fiberRootNode will point to the Fiber tree corresponding to the rendered content on the current page, that is, the current Fiber tree.
Because it is
- Next enter renderStage, according to the components returnedJSXCreate Fiber nodes in memory and connect them together to build a Fiber tree, which is calledworkInProgress Fibertree. When constructing the workInProgress Fiber tree, it will try to reuse the properties of the existing Fiber node in the current Fiber tree. When the first screen is rendered, only the rootFiber has the corresponding current fiber.
- The completed workInProgress Fiber tree is in commitThe stage is rendered to the page.
2. Components update Time
- When we click divThe node triggers a state change and starts a new onerenderStage and build a newworkInProgress Fibertree.
- workInProgress FiberTree inrenderEnter after the stage is completedcommitThe stage is rendered on the page. After rendering, the workInProgress Fiber tree becomes the current Fiber tree.