React design ideas for React source code learning

React design ideas for React source code learning

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 response
The 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

60Hz
, Ie every (1000ms/60Hz)
16.6ms
The browser refreshes once. At this
16.6ms
To accomplish the following things:

  1. 1. the JS script is executed;
  2. Execute requestAnimationFrame (rAF), that is, before each drawing, the rAF callback will be executed;
  3. Perform Layout operations, including calculating layout and updating layout;
  4. 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;
  5. Next in the idle phase (Idle Peroid), can be executed at this time
    requestIdleCallback
    Tasks registered in

If we do not complete within 16.6ms, the page will appear to a certain extent

Caton
phenomenon.

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

this.setState, this.forceUpdate, ReactDOM.render
Wait for the API to trigger an update.

When an update occurs, Reconciler will do the following:

  1. Call the render method of the function component or the class component, and it will return
    JSX
    Converted to
    Virtual DOM
    ;
  2. will
    Virtual DOM
    Compare with the virtual DOM at the time of the last update;
  3. Find out the virtual DOM that has changed in this update by comparison;
  4. 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:

  1. ReactNative: Render App native components;
  2. ReactTest: renders pure JS objects for testing;
  3. ReactArt: Render to Canvas, SVG or VML (IE8);

Disadvantages of React 15 architecture

In React 15 version Reconciler is called

"Stack" reconciler
,it will
mount (component mount)
Call mountComponent when
update (component update)
The component will call updateComponent. Both methods will use
Recursive update
Subassembly,
Unable to achieve asynchronous interruptible update, scheduling priority
. If the level of the component tree is very deep, recursion will take up a lot of thread time, resulting in too long JS execution time, exceeding 16.6ms (mainstream browser refresh frequency is 60Hz, that is, every (1000ms/60Hz)), which may easily cause page jam .

React 16 architecture

The React 16 architecture can be divided into three layers:

  • Scheduler
    Scheduling tasks
    priority
    , High-priority tasks enter the Reconciler first;
  • Reconciler (Coordinator)
    Responsible for finding the changed components;
  • Renderer
    Responsible for rendering the changed components to the page;

Scheduler

We know that some browsers have already implemented

requestIdleCallback
, Let us know when the browser has time left. However, React has given up its use due to the following factors:

  1. Browser compatibility;
  2. The trigger frequency is unstable;

Based on the above reasons, the React team implemented requestIdleCallback by itself

polyfill
, Which is Scheduler . In addition to the function of triggering callbacks when idle, Scheduler also provides
Multiple scheduling priorities for task setting
.

Reconciler (Coordinator)

The file is located at: github.com/facebook/re...

From

React15
To
React16
, A major purpose of the reconciler (Reconciler) refactoring is: the old
Synchronization Update
The architecture becomes
Asynchronous interruptible update
. The update may be interrupted during the execution (the browser time slice is exhausted or a higher-quality task is interrupted), and the intermediate state of the previous execution will be restored when the execution can continue. Give up in a timely manner
CPU
The right of execution allows the browser to respond to user interactions in a timely manner.

Generator

Why didn't the React team use Generator to achieve asynchronous interruptible? React team member

sebmarkbage
In 16 years
issue
Fiber Principles: Contributing To Fiber provided the answer. The main reasons for giving up are as follows:

  1. Generator is contagious, and other functions of the context need to be changed if Generator is used.
  2. The generator is stateful and cannot be restored midway.

Fiber reconciler

"Fiber" reconciler
It is a new attempt to solve the inherent problems in the stack reconciler and at the same time solve some historical problems. Fiber has become the default reconciler since React 16.

Fiber
Contains three meanings:

  1. As an architecture, before
    React15
    of
    Reconciler
    It is executed in a recursive manner, and the data is stored in the recursive call stack, so it is called
    stack Reconciler
    . React16
    Reconciler
    Based on Fiber node implementation, known as
    Fiber Reconciler
    .
  2. As
    Static data structure
    Say, each Fiber node corresponds to one
    React element
    ,use
    Linked list
    achieve. The type of the component, the corresponding DOM node and other information are saved.
  3. As
    Dynamic unit of work
    In 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:

  1. Ability to slice and process interruptible tasks.
  2. Ability to adjust priority, reset and reuse tasks.
  3. Ability to interleave between parent elements and child elements to support layout in React.
  4. Ability to return multiple elements in render().
  5. 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

Fiber
Tree structure:

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

current Fiber
Tree, being
In memory
The constructed Fiber tree is called
workInProgress Fiber
tree.

The Fiber node in the current Fiber tree is called

current fiber
, The Fiber node in the workInProgress Fiber tree is called
workInProgress fiber
, They passed
alternate
Property connection.

currentFiber.alternate === workInProgressFiber; workInProgressFiber.alternate === currentFiber; Copy code

The root node of the React application uses

current
Pointers in different fiber trees
rootFiber
Switch between to complete the switching of the current Fiber tree.

when

workInProgress Fiber
The tree is built and handed over to
Renderer
After rendering on the page, the current pointer of the application root node points to the workInProgress Fiber tree. At this time, the workInProgress Fiber tree becomes the current Fiber tree.

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.render
    Will create
    fiberRootNode
    with
    rootFiber
    . Where fiberRootNode is
    The root node of the entire application
    , RootFiber is where
    The 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. but
    There is only one root node for the entire application
    ,That is
    fiberRootNode
    . 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

Above the fold rendering
, There is no DOM mounted on the page, so the rootFiber pointed to by fiberRootNode.current does not have any child Fiber nodes.
At this time, the current Fiber tree is empty
.

  • Next enter
    render
    Stage, according to the components returned
    JSX
    Create Fiber nodes in memory and connect them together to build a Fiber tree, which is called
    workInProgress Fiber
    tree. 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
    commit
    The stage is rendered to the page.

2. Components
update
Time
  • When we click
    div
    The node triggers a state change and starts a new one
    render
    Stage and build a new
    workInProgress Fiber
    tree.

  • workInProgress Fiber
    Tree in
    render
    Enter after the stage is completed
    commit
    The stage is rendered on the page. After rendering, the workInProgress Fiber tree becomes the current Fiber tree.

Reference