react parsing: update in render

Keywords: Javascript React

Thank yck: analyze the source code of React , this article is based on reading his article, disassembling and processing his article, adding my own understanding and examples for everyone to understand. Think yck It's really great. The React version is 16.8.6. For reading the source code, you can go to Source code analysis of yck react

Permanent links to this article: react parsing: update in render (4)

Previous chapter Say that there is no root data node, that is, throughcreateFiberRoot function to create a FiberRoot , the FiberRoot object is the starting point of the whole React application, and also records all kinds of information during the update process of the whole React application.

What we'll talk about next is what happens when root is created.

legacyRenderSubtreeIntoContainer function

The following links up the previous part. I don't know how to view itPrevious chapter.

yck: ReactDOM source code 554 lines legacyRenderSubtreeIntoContainer

function legacyRenderSubtreeIntoContainer(
  parentComponent: ?React$Component<any, any>,
  children: ReactNodeList,
  container: DOMContainer,
  forceHydrate: boolean,
  callback: ?Function,
) {
    // When initializing, the container must not have the "react rootcontainer" property
    let root: Root = (container._reactRootContainer: any);
    if (!root) {
        // Omit the create root section
        
        unbatchedUpdates(() => {
            if (parentComponent != null) {
                root.legacy_renderSubtreeIntoContainer(
                    parentComponent,
                    children,
                    callback,
                );
            } else {
                root.render(children, callback);
            }
        });
    }
}

When root is just created, parentComponent is generally null;

The unbatchedUpdates function is used here to tell React not to batch update, that is, not to merge multiple setstates into one;
(we'll talk about setState later)

In this case, the root.render function is actually called. Root is the ReactRoot instance object, that is, the root.render function = = ReactRoot.prototype.render function is called.

ReactRoot.prototype.render function

yck: ReactRoot source code line 377 ReactRoot.prototype.render

ReactRoot.prototype.render = function(
  children: ReactNodeList,
  callback: ?() => mixed,
): Work {
  // This is FiberRoot.
  const root = this._internalRoot;
  const work = new ReactWork();
  callback = callback === undefined ? null : callback;

  // If there is a callback, push it into the array in work
  if (callback !== null) {
    work.then(callback);
  }
  // Work. Oncommit is used to execute all callback functions.
  updateContainer(children, root, null, work._onCommit);
  return work;
};

The parameter children in the function is the ReactElement node object, and callback is the callback function. The main function of the ReactWork instance object is to maintain a callback array, which can be viewed. yck: ReactWork source code line 327 , if there is a callback in the incoming parameter, it will be attached to the ReactWork instance object;

Let's see what the updateContainer function does.

updateContainer function

yck: ReactFiberReconciler source code 284 line updateContainer

export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): ExpirationTime {
  const current = container.current;
  // computing time
  const currentTime = requestCurrentTime();
  // expirationTime represents priority, the higher the number, the higher the priority
  // sync has the largest number, so it has the highest priority
  const expirationTime = computeExpirationForFiber(currentTime, current);
  return updateContainerAtExpirationTime(
    element,
    container,
    parentComponent,
    expirationTime,
    callback,
  );
}

container.current is to take out the RootFiber object from the FiberRoot, and currentTime is the current time when the React application is initialized. **expirationTime literally means expiration time. I will spend a chapter to introduce these two times, which are also the focus of React application task scheduling.

scheduleRootUpdate function

The updateContainerAtExpirationTime function actually calls the scheduleRootUpdate function. Let's talk about the role of the scheduleRootUpdate function.

Yck: realfiberreconciler source code line 114 scheduleRootUpdate

function scheduleRootUpdate(
  current: Fiber,
  element: ReactNodeList,
  expirationTime: ExpirationTime,
  callback: ?Function,
) {
  // Create an update, which is an object with several internal properties
  const update = createUpdate(expirationTime);
  update.payload = {element};

  // Callback function in render 
  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    update.callback = callback;
  }

  flushPassiveEffects();
  // To queue an update is to create or get a queue (linked list structure) and then add a node to the linked list.
  enqueueUpdate(current, update);
  scheduleWork(current, expirationTime);

  return expirationTime;
}

Here are the properties in the update object:

// update object properties
export type Update<State> = {
  // Expiration time of update
  expirationTime: ExpirationTime,

  // export const UpdateState = 0;
  // export const ReplaceState = 1;
  // export const ForceUpdate = 2;
  // export const CaptureUpdate = 3;
  // Specify the type of update with the above values
  tag: 0 | 1 | 2 | 3,
  // Update content, such as the first parameter received by 'setState'
  payload: any,
  // The corresponding callbacks, 'setState', and 'render' all have
  callback: (() => mixed) | null,

  // Point to next update
  next: Update<State> | null,
  // Point to next ` side effect`
  nextEffect: Update<State> | null,
};

The udate object will be inserted into the task queue maintained by the React application, regardless of whether you are updating the React application caused by setState or React dom.render. The core function of this function is to create or get a queue, and then insert the update object into the queue to update. The scheduleWork function is the job scheduling thing.

More:

React resolution: React.createElement(1)

React analysis: React.Children(2)

react parsing: render's FiberRoot(3)

Reference resources:

yck: dissecting the source code of React

Jokcy's "React source code analysis": react.jokcy.me/

ps: by the way, my personal public number: Yopai. You can pay attention to it if you are interested, update it irregularly every week, and share it to increase the happiness of the world.

Posted by Ludichrist on Wed, 23 Oct 2019 21:17:37 -0700