In the last article we gave an example, but only said React. CreateElement, leaving reactdom.render. ReactDOM. Render is so loaded that it must be disassembled.
ReactDOM. Render can be divided into three parts according to function and call order: schedule, reconciliation, and render.
Here’s a quick rundown of what they do:
- Scheduler: Indicates the priority of the task that is scheduled. The high task moves to the Reconciliation phase
- Reconciliation: Identifies the components that have changed
- Render: Render the changed component to the page
Because there are so many things to do, the call stack of Reactdom. render is very deep, and it is easy to make a loop by directly looking at the code one by one, so I found an interface generated by React and recorded it using Chrome’s Performance. You can see its call stack as follows:
The three boxes in the picture above basically represent three functional blocks.
We’re not going to follow the order in which the three function blocks are called, because it might be difficult to learn the React source code that way, so I’m going to try to figure out what Fiber is, which is something that runs through.
What is the Fiber
Fiber is a special data structure (a special linked list with parents and brothers) and an implementation of a virtual DOM that supports tasks with different priorities, can be interrupted and recovered, and can reuse the previous intermediate state when recovered.
A ReactElement corresponds to a Fiber object.
The source code
Fiber source in the packages/react – the reconciler/SRC/ReactFiber. New. Js directory
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;
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
// Scheduling priority is related
this.lanes = NoLanes;
this.childLanes = NoLanes;
// Point to the corresponding fiber from the next update
this.alternate = null;
// Omit the following code
}
Copy the code
Explain a few of the more important attributes:
- Tag A tag of the current node type. For example, the root node tag is 3. The function component tag is 0.
ReactWorkTags.js
Well defined - Key is the key property
- stateNode
Fiber
The corresponding real DOM node - ElementType is a tag for a real DOM element, such as h3, div, and so on
- Return, child and sibling are respectively the parent, son and brother
fiber
node - Several effects-related markers that record whether changes are needed,
ReactFiberFlags.js
There is a complete definition - Lanes are used in the scheduling phase
- Alternate is from the last rendering
fiber
Double cache
What is dual caching
When we draw an animation on Canvas, we call ctx.clearRect to clear the previous frame before each frame is drawn.
If the calculation amount of the current frame is large, there will be a long gap between the clearance of the previous frame and the drawing of the current frame, and a white screen will appear.
To solve this problem, we can draw the animation of the current frame in memory, and directly replace the previous frame with the current frame after the drawing is finished. Because the calculation time between the replacement of two frames is saved, there will be no flicker from the white screen to the screen.
This technique of building in memory and replacing directly is called dual caching.
Double cache in React
React uses a “dual cache” to build and replace the Fiber tree — which corresponds to creating and updating the DOM tree.
There are at most two Fiber trees in React. The Fiber tree 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. They are connected through alternate properties.
Root Fiber
React creates a FiberRootNode and rootFiber when it first loads the interface.
FiberRootNode is the root node of the entire container, which has only one.
RootFiber is the root node of the component tree. It is also a FiberNode. There can be multiple component trees, and different component trees have different root nodes.
The FiberRootNode current property points to the Fiber tree corresponding to the rendered content on the current page, the Current Fiber tree.
At the time of first rendering, no DOM had been mounted on the page, so the FiberRootNode’s current property was empty and the Current Fiber tree was empty.
Next, enter the Reconciliation phase of the Render phase, and according to the JSX returned by components, create Fiber nodes in memory in turn and connect them together to build a Fiber tree, which is called the workInProgress Fiber tree.
During the construction of the workInProgress Fiber tree, the properties within the existing Fiber nodes in the current Fiber tree are tried to be multiplexed, and only the corresponding current Fiber (i.e. Rootfiber.alternate) exists in the first screen rendering.
Below is FiberRootNode source, path of packages/react – the reconciler/SRC/ReactFiberRoot. New. Js
function FiberRootNode(containerInfo, tag, hydrate) {
this.tag = tag;
this.containerInfo = containerInfo;
this.pendingChildren = null;
this.current = null;
this.pingCache = null;
this.finishedWork = null;
this.timeoutHandle = noTimeout;
this.context = null;
this.pendingContext = null;
this.hydrate = hydrate;
this.callbackNode = null;
this.callbackPriority = NoLane;
this.eventTimes = createLaneMap(NoLanes);
this.expirationTimes = createLaneMap(NoTimestamp);
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;
this.entangledLanes = NoLanes;
this.entanglements = createLaneMap(NoLanes);
// Omit part of the code
}
Copy the code
The createHostRootFiber function helps initialize the current property.
The instance
import React from 'react';
import ReactDOM from 'react-dom';
function Com() {
return (
<div style={{ color: 'red' }}>
<h3>Hello, Eagle!</h3>
</div>
)
}
ReactDOM.render(
<Com />.document.getElementById('root'));Copy the code
Here is a demonstration of some of the FiberNode properties for div:
alternate: null
child: FiberNode {
alternate: null
child: null
childLanes: 0
dependencies: null
elementType: "h3"
firstEffect: null
flags: 0
index: 0
key: null
lanes: 1
lastEffect: null
memoizedProps: null
memoizedState: null
mode: 8
nextEffect: null
pendingProps: {children: "Hello, eagle!"}
ref: null
return: FiberNode {tag: 5.key: null.elementType: "div".type: "div".stateNode: null,... }selfBaseDuration: 0
sibling: null
stateNode: null
tag: 5
type: "h3"
updateQueue: null
}
childLanes: 0
dependencies: null
elementType: "div"
firstEffect: null
flags: 2
index: 0
key: null
lanes: 0
lastEffect: null
memoizedProps: null
memoizedState: null
mode: 8
nextEffect: null
pendingProps: {
children: {$$typeof: Symbol(react.element), type: "h3".key: null.ref: null.props: {... },... }style: {color: "red"}}ref: null
return: FiberNode {
alternate: FiberNode {tag: 3.key: null.elementType: null.type: null.stateNode: FiberRootNode,... }child: FiberNode {tag: 5.key: null.elementType: "div".type: "div".stateNode: null,... }childLanes: 0
dependencies: null
elementType: null
firstEffect: null
flags: 0
index: 0
key: null
lanes: 0
lastEffect: null
mode: 8
nextEffect: null
pendingProps: null
ref: null
return: null
sibling: null
stateNode: FiberRootNode {tag: 0.containerInfo: div#root, pendingChildren: null.current: FiberNode, pingCache: null,... }tag: 3
type: null
updateQueue: {baseState: {... },firstBaseUpdate: null.lastBaseUpdate: null.shared: {... },effects: null}}sibling: null
stateNode: null
tag: 5
type: "div"
updateQueue: null
Copy the code
Here are a few things you can see from this object:
- The current
fiber
的return
Property is its parent node, which is also the root node of the component, and alsoFiberNodeRoot
的current
Properties; - The current
fiber
Of the parent nodestateNode
Attributes correspond toFiberNodeRoot
You can see hiscontainerInfo
Is the root node of our real DOM; - The current
fiber
的pendingProps
Properties contain the properties of the current node; - The current
fiber
的child
The property is its child node, which is oursh3
Node.