zoukankan      html  css  js  c++  java
  • React Fiber源码分析 第一篇

     先附上流程图一张

    先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来可以看到element,container,callback分别代表着react元素、DOM原生元素,回调函数

    render实际上调用的是 legacyRenderSubtreeIntoContainer函数

    render: function (element, container, callback) {
      return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
    }

    legacyRenderSubtreeIntoContainer 这个函数, 实际上是初始化了root, 并调用了root.render方法, 而root是由legacyCreateRootFromDOMContainer函数返回的

    function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
      var root = container._reactRootContainer;
      if (!root) {
        // 初始化root
        root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);// Initial mount should not be batched.
        unbatchedUpdates(function () {
          if (parentComponent != null) {
            root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
          } else {
    // 调用root的render方法 root.render(children, callback); } }); }
    else { ...... } }

    从代码中看出, legacyCreateRootFromDOMContainer执行了两个操作, 一个是清除掉所有的子元素, 另外一个则是返回了一个 ReactRoot实例, 这里需要注意一点, root默认是同步更新的, 即isAsync 默认为false

    function legacyCreateRootFromDOMContainer(container, forceHydrate) {
      ...// 清除所有子元素
      if (!shouldHydrate) {
        var warned = false;
        var rootSibling = void 0;
        while (rootSibling = container.lastChild) {
          {
            if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {
              warned = true;
            }
          }
          container.removeChild(rootSibling);
        }
      }// 默认为同步状态
      var isAsync = false;
      return new ReactRoot(container, isAsync, shouldHydrate);
    }

    ReactRoot中, 我们把createContainer返回值赋给了 实例的_internalRoot, 往下看createContainer

    function ReactRoot(container, isAsync, hydrate) {
      var root = createContainer(container, isAsync, hydrate);
      this._internalRoot = root;
    }

    createContainer看出, createContainer实际上是直接返回了createFiberRoot, 而createFiberRoot则是通过createHostRootFiber函数的返回值uninitializedFiber,并将其赋值在root对象的current上, 这里需要注意一个点就是,uninitializedFiberstateNode的值是root, 即他们互相引用

    function createContainer(containerInfo, isAsync, hydrate) {
      return createFiberRoot(containerInfo, isAsync, hydrate);
    }
    function createFiberRoot(containerInfo, isAsync, hydrate) {
      // 创建hostRoot并赋值给uninitiallizedFiber
      var uninitializedFiber = createHostRootFiber(isAsync);
      // 互相引用
      var root = void 0;
      root = {
          current: uninitializedFiber,
          ...
      };
     uninitializedFiber.stateNode = root; 

    最后是返回了一个fiberNode的实例, 在这里我们可以看到mode这个字段, 由于在一开始就将isAsync初始化为false, 所以mode实际上就代表了同步

    在这里, 整理一下各个实例的关系, 

     rootReactRoot实例,

     root._internalRoot 即为fiberRoot实例,

     root._internalRoot.current即为Fiber实例,

     root._internalRoot.current.stateNode = root._internalRoot

    function createHostRootFiber(isAsync) {
      var mode = isAsync ? AsyncMode | StrictMode : NoContext;
      return createFiber(HostRoot, null, null, mode);
    }
    var createFiber = function (tag, pendingProps, key, mode) {
      return new FiberNode(tag, pendingProps, key, mode);
    };
    function FiberNode(tag, pendingProps, key, mode) {
      // Instance
      this.tag = tag;
      this.key = key;
      this.type = null;
      this.stateNode = null;
    
      // Fiber
      this.return = null;
      this.child = null;
      this.sibling = null;
      this.index = 0;
    
      ...
    }

    初始化完成, 接下来就是root.render执行了, 在这里, 先暂时忽略ReactWork, 把work._onCommit当成一个回调函数即可, 可以看到, rootFiberRoot实例被当成参数传入了updateContsainer里面, 往下看updateContainer

    ReactRoot.prototype.render = function (children, callback) {
      var root = this._internalRoot;
      var work = new ReactWork();
      callback = callback === undefined ? null : callback;
      if (callback !== null) {
        work.then(callback);
      }
      updateContainer(children, root, null, work._onCommit);
      return work;
    };

    updateContsainer里面使用了 currentTime 和 expirationTime

     currentTime是用来计算expirationTime,

     expirationTime代表着优先级, 留在后续分析,

    这里我们知道是同步更新 即 expirationTime = 1. 紧接着调用了updateContainerAtExpirationTime

    function updateContainer(element, container, parentComponent, callback) {
      var current$$1 = container.current;
      var currentTime = requestCurrentTime();
      var expirationTime = computeExpirationForFiber(currentTime, current$$1);
      return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback);
    }

    updateContainerAtExpirationTimecurrent(即Fiber实例)提取出来, 并作为参数传入调用scheduleRootUpdate

    function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) {
      // TODO: If this is a nested container, this won't be the root.
      var current$$1 = container.current;
      ...
      return scheduleRootUpdate(current$$1, element, expirationTime, callback);
    }

    到了这里告一段落, scheduleRootUpdate接下来就是React新版本异步渲染的核心了, 留在下一篇继续解读

  • 相关阅读:
    PAIP HTML的调试与分析工具
    paip.输入法编程一级汉字1000个
    paip.DEVSUIT ADMIN 初次使用时出现两个LICENSE提醒
    int main(int argc,char *argv[])中参数的意义
    深入理解C语言小记
    曲线拟合的最小二乘法
    C51 bit和sbit的区别
    曲线拟合的最小二乘法
    有关verilog truncated value with size 32 to match size of target警告的处理
    C51 bit和sbit的区别
  • 原文地址:https://www.cnblogs.com/Darlietoothpaste/p/9692291.html
Copyright © 2011-2022 走看看