ReactRoot与ReactWork源码分析

栏目: 编程工具 · 发布时间: 5年前

内容简介:在文章中如有不当之处,欢迎交流指点。react版本在上篇分析后,最终得到如下函数调用过程。

ReactDOM.render源码解析-1 中介绍了第一次render的基本过程的一部分,其中产生了ReactRoot和ReactWork两个类的实例。本文介绍下ReactRoot,ReactWork源码,只关注第一次调用render的过程。

文章中如有不当之处,欢迎交流指点。react版本 16.8.2 。在源码添加的注释在github react-source-learn 的learn分支。

回顾

在上篇分析后,最终得到如下函数调用过程。

ReactRoot与ReactWork源码分析

在render方法中调用了legacyRenderSubtreeIntoContainer。

在legacyRenderSubtreeIntoContainer中调用legacyCreateRootFromDOMContainer获得了ReactRoot的实例root,然后调用unbatchedUpdates,其中的回调函数中调用了root.render方法。RootRoot是什么?他的render方法做了什么?

代码分析

通过对ReactRoot和ReactWork代码的简单分析,笔者做了如下类图,以帮助了解这两个类有哪些属性和方法。

ReactRoot与ReactWork源码分析

有很多东西不是第一次调用render用到的,这里只关注第一次render所需要调用方法或使用的属性。

ReactRoot

这个类主要介绍其构造函数和render方法,构造函数是new时调用的,render方法是unbatchedUpdates的回调函数中使用的。代码如下:

// ReactRoot构造函数
// 构造函数主要是挂了一个_internalRoot在this上
function ReactRoot(
  container: DOMContainer, // dom节点
  isConcurrent: boolean, // 第一次render为false
  hydrate: boolean, // 第一次render为false
) {
  // 这个createContainer是packages/ReactFiberReconciler中的方法,
  // 返回的是一个OpaqueRoot的东西
  const root = createContainer(container, isConcurrent, hydrate);
  this._internalRoot = root;
}

// render实例方法 new 了ReactWork, 调用了then方法
// 调用了updateContainer方法
// 返回了ReactWork实例
ReactRoot.prototype.render = function(
  children: ReactNodeList,  // element
  callback: ?() => mixed, // ReactDOM.render(element, container, callback); callback
): Work {
  const root = this._internalRoot;
  const work = new ReactWork();
  callback = callback === undefined ? null : callback;
  if (callback !== null) {
    work.then(callback);
  }

  // updateContainer是packages/react-reconciler/ReactFiberReconciler.js中的
  // 一个方法,后边再说
  updateContainer(children, root, null, work._onCommit);
  return work;
};

先看构造函数

第一次render时new ReactRoot位于legacyCreateRootFromDOMContainer中,其调用代码如下:

return new ReactRoot(container, isConcurrent, shouldHydrate)

container是我们调用ReactDOM.render时的第二个参数,一个dom,但是里边的子节点已被处理了,isConcurrent这里是写死的false,shouldHydrate上文分析过,为false。

再看ReactRoot的构造函数,他调用了一个createContainer并将返回值挂到了_internalRoot属性。这个createContainer将在下一篇分析。

看下render方法

我们先看看第一次render是调用他的代码, root.render(children, callback); ,其中children是ReactDOM.render的第一个参数,是个ReactElement, callback是第三个参数,通常不传。

这个render方法主要做了如下事:

  • new ReactWork -> work
  • 调用work的then方法
  • 调用updateContainer
  • 返回work

这里值得注意的是ReactWork类,这个将在后文分析;还有updateContainer,这个将在后面的文章分析,这里搞清楚第一调用时的参数给的啥,即ReactElement,createContainer返回的root,null,ReactWork实例的_onCommit方法。

ReactWork

ReactWork的方法在第一次render时都有可能被调用到,如下代码为ReactWork类的定义:

// ReactWork的构造函数
function ReactWork() {
  this._callbacks = null;
  this._didCommit = false;
  // TODO: Avoid need to bind by replacing callbacks in the update queue with
  // list of Work objects.
  this._onCommit = this._onCommit.bind(this);
}

// then方法
ReactWork.prototype.then = function(onCommit: () => mixed): void {
  if (this._didCommit) { // 第一次render调用then时为false, 不走这里
    onCommit();
    return;
  }
  let callbacks = this._callbacks;
  if (callbacks === null) { // 第一次render是调用走这里
    callbacks = this._callbacks = [];
  }
  callbacks.push(onCommit);
};

// _onCommit方法
ReactWork.prototype._onCommit = function(): void {
  if (this._didCommit) { // 第一次render不走这里
    return;
  }
  this._didCommit = true;
  // 这个callbacks是调用.then方法是传进去的函数
  const callbacks = this._callbacks;
  if (callbacks === null) {
    return;
  }
  // TODO: Error handling.
  for (let i = 0; i < callbacks.length; i++) {
    const callback = callbacks[i];
    invariant(
      typeof callback === 'function',
      'Invalid argument passed as callback. Expected a function. Instead ' +
        'received: %s',
      callback,
    );
    callback();
  }
};

构造函数

构造函数不接受参数,做了一些初始化工作

then方法

then方法调用时是 work.then(callback); ,callback是ReactDOM的第三个参数

then方法的作用就是维护一个_callbacks队列,每次都将传进去的函数入队

_onCommit方法

这个方法的调用代码 updateContainer(children, root, null, work._onCommit) ,其实是updateContainer的最后一个参数。

在这个里边将_didCommit置为true,回顾上边的ReactRoot的render方法,意味着这个方法被调用后在调ReactRoot.render是会直接执行callback的而不是入队。

然后是将_callbacks中的方法都执行了一遍。

小结

从上文的分析来看,接下来的重点是分析updateContainer这个方法,ReactWork的then方法是将callback入队,_onCommit是执行_callbacks中的所有方法,而调用_onCommit的是在updateContainer中,updateContainer实在ReactRoot.render方法中调用的,因此updateContainer应该是一个非常重要的东西。另外,ReactRoo.render方法是在unbatchedUpdates的回调函数中调用的,unbatchedUpdates也是一个参与后面调度的关键。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图形程序开发人员指南

图形程序开发人员指南

Michael Abrash / 前导工作室 / 机械工业出版社 / 1998 / 128

Michael Abrash's classic Graphics Programming Black Book is a compilation of Michael's previous writings on assembly language and graphics programming (including from his "Graphics Programming" column......一起来看看 《图形程序开发人员指南》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具