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也是一个参与后面调度的关键。


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

查看所有标签

猜你喜欢:

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

数据挖掘技术

数据挖掘技术

[美]MichaelJ.A.B / 别荣芳、尹静、邓六爱 / 机械工业 / 2006-7 / 49.00元

本书是数据挖掘领域的经典著作,数年来畅销不衰。全书从技术和应用两个方面,全面、系统地介绍了数据挖掘的商业环境、数据挖掘技术及其在商业环境中的应用。自从1997年本书第1版出版以来,数据挖掘界发生了巨大的变化,其中的大部分核心算法仍然保持不变,但是算法嵌入的软件、应用算法的数据库以及用于解决的商业问题都有所演进。第2版展示如何利用基本的数据挖掘方法和技术,解决常见的商业问题。 本书涵盖核心的数......一起来看看 《数据挖掘技术》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具