React 源码探源 2 Mount 复杂的例子

2021-06-21  本文已影响0人  吴摩西

接第一章React 源码探源 1 Mount.

本文中有些结论处于笔者的猜测,如有不妥之处,欢迎指出。

源码

先看一个例子:

function Dev() {
  const [count, setCount] = React.useState(0);
  return (<div id="div">
    <button id="btn" onClick={() => {
       setCount(function add(c) { return c + 1; });
       setCount(function double(c) { return c * 2; });
       setCount(function minus(c) { return c - 1; });
      }}>click me</button>
    <div>the new text is <span>{count}</span></div>
  </div>);
}
ReactDOM.render(
  <div>
    <h1>Hello World!</h1>
    <Dev />
  </div>
  , document.getElementById('container'));

Render 阶段

先看 Render 阶段的 fiber tree 结果,如下


render 的结果

如第一章所述,在第一次 commit 之前,fiberRoot 下面的 current 还是空的,所有的 fiber 节点都在 fiberRoot.current.alternate,fiber 中的几个重要的属性如下:

另外需要注意的是, buttononClick 属性并没有在 fiber 树中有特殊体现,只是在 DOM 节点中有属性对其进行了存储。onClick 属性也没有对 button 添加对应的事件监听。

Commit 阶段

本例中没有 useEffect 或者 useLayoutEffect 的调用,整体的 commit 阶段比较简单。

  1. commitMutationEffects,这是主要的 commit 阶段,就是将 fiber 树 commit 到 DOM 上的阶段
  2. commitMutationEffects_begin,从代码中可以看到,这个阶段是在插入或者更新之前先做一些删除工作,咱们会在后续的系列中探索这里面的工作。
  3. commitMutationEffects_complete,可以看到这是一个递归向上的过程,本例中中只执行了一次,咱们会在后续的系列中探索这里的工作。
  4. commitMutationEffectsOnFiber,这一阶段检查 fiber(HostRoot) 下的第一个子节点 fiber(HostComponent) 的 flags,发现其中有 Placement 的标记。执行 Placement 的操作
  5. commitPlacement,在此阶段执行插入的操作,会先检查此 fiber 是 HostRoot,找到其父节点对应的 containerInfor,即找到需要插入的地方。
  6. insertOrAppendPlacementNodeIntoContainer,最后执行此函数来将 fiber(HostComponent) 下的 stateNode (div) 插入到 containerInfor

总结

本节通过一个例子,了解到了 ReactDOM.render 的主要流程 rendercommit。对 fiber 的 主要结构及主要的 commit 流程有所描述。在下一节,笔者计划再次通过此例探索 React 更新时的主要流程。本节中涉及到的过程还有很多的细节未能描述,会在后续的系列中继续探究。

上一篇 下一篇

猜你喜欢

热点阅读