React fiber 源码分析1(版本16.6.3)

ReactDom

1,根据react的测试用例,直接打断点,看下reactdom.render()到底是如何工作的,这里可以先忽略DEV, 因为这里大多数都是一些检测,一些warning提示,可以先理清出整体脉络,然后再去关注这些点.
文件地址:
packages/react-dom/src/tests/ReactDOM-test.js
打上断点

document.body.appendChild(container);
    try {
      // 这里打上断点
      ReactDOM.render(, container);
      buttonRef.click();
      expect(count).toBe(1);
    } finally {
      document.body.removeChild(container);
    }

文件地址:
packages/react-dom/src/client/ReactDOM.js

render(
    element: React$Element,
    container: DOMContainer,
    callback: ?Function,
  ) {
    return legacyRenderSubtreeIntoContainer(
      null,
      element,
      container,
      false,
      callback,
    );
  },

可以看到这里没有做过多的处理,然后直接就转到了legacyRenderSubtreeIntoContainer
这里的legacy是遗产遗留的意思,不知道是不是以后会放弃掉。

function legacyRenderSubtreeIntoContainer(
  // null
  parentComponent: ?React$Component,
  // 子元素,这里是div
  children: ReactNodeList,
  // 这里是容器
  container: DOMContainer,
  // 是否是服务器服务端
  forceHydrate: boolean,
  // null
  callback: ?Function,
) {
  // TODO: Ensure all entry points contain this check
  // 准备做,确保所有的都先检查是否是正确的
  invariant(
    isValidContainer(container),
    'Target container is not a DOM element.',
  );
  // 在开发模式下,检测,如果不符合一堆warning
  if (__DEV__) {
    topLevelUpdateWarnings(container);
  }

  // TODO: Without `any` type, Flow says "Property cannot be accessed on any
  // member of intersection type." Whyyyyyy.
  // 是否存在当前的根节点
  let root: Root = (container._reactRootContainer: any);
  if (!root) {
    // Initial mount
    // 创建根节点
    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
      container,
      forceHydrate,
    );
    // null
    if (typeof callback === 'function') {
      const originalCallback = callback;
      callback = function() {
        const instance = DOMRenderer.getPublicRootInstance(root._internalRoot);
        originalCallback.call(instance);
      };
    }
    // Initial mount should not be batched.
    // 初始化不能是成批的,这里是向真实的dom里边去插入dom
    DOMRenderer.unbatchedUpdates(() => {
      // 有没有真实的dom父元素
      if (parentComponent != null) {
        root.legacy_renderSubtreeIntoContainer(
          parentComponent,
          children,
          callback,
        );
      } else {
        root.render(children, callback);
      }
    });
  } else {
    // null
    if (typeof callback === 'function') {
      const originalCallback = callback;
      callback = function() {
        const instance = DOMRenderer.getPublicRootInstance(root._internalRoot);
        originalCallback.call(instance);
      };
    }
    // Update,
    // 和上面同样的操作
    if (parentComponent != null) {
      root.legacy_renderSubtreeIntoContainer(
        parentComponent,
        children,
        callback,
      );
    } else {
      root.render(children, callback);
    }
  }
  // 获取container的元素
  return DOMRenderer.getPublicRootInstance(root._internalRoot);
}

可以看到如下图,这里的container就是一个对象,如图所示:


image.png

可以看到当没有root的时候,首先通过legacyCreateRootFromDOMContainer来创建root,然后在进行其他操作。
所以我们去跟进 legacyCreateRootFromDOMContainer

function legacyCreateRootFromDOMContainer(
  container: DOMContainer,
  forceHydrate: boolean,
): Root {
  // 是不是服务器渲染
  const shouldHydrate =
    forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
  // First clear any existing content.
  // 首先清空container的内容
  if (!shouldHydrate) {
    let warned = false;
    let rootSibling;
    // 循环清空
    while ((rootSibling = container.lastChild)) {
      if (__DEV__) {
        if (
          !warned &&
          rootSibling.nodeType === ELEMENT_NODE &&
          (rootSibling: any).hasAttribute(ROOT_ATTRIBUTE_NAME)
        ) {
          warned = true;
          warningWithoutStack(
            false,
            'render(): Target node has markup rendered by React, but there ' +
              'are unrelated nodes as well. This is most commonly caused by ' +
              'white-space inserted around server-rendered markup.',
          );
        }
      }
      container.removeChild(rootSibling);
    }
  }
  if (__DEV__) {
    if (shouldHydrate && !forceHydrate && !warnedAboutHydrateAPI) {
      warnedAboutHydrateAPI = true;
      lowPriorityWarning(
        false,
        'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
          'will stop working in React v17. Replace the ReactDOM.render() call ' +
          'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
      );
    }
  }
  // Legacy roots are not async by default.
  const isAsync = false;
  return new ReactRoot(container, isAsync, shouldHydrate);
}

这里比较简单,就是简单的通过container.lastchild循环来清除container的所有内容,因为我们的属于首次渲染,container里边不包含任何元素,所以直接执行到了
return new ReactRoot(container, isAsync, shouldHydrate);
通过ReactRoot来创建一个root。
下一步直接追踪到ReactRoot

function ReactRoot(container: Container, isAsync: boolean, hydrate: boolean) {
  const root = DOMRenderer.createContainer(container, isAsync, hydrate);
  this._internalRoot = root;
}

这里也很简单,通过DOMRenderer.createContainer创建root,然后挂载到_internalRoot上面。
然后可以到DOMRenderer.createContainer,看下里边是做什么?

通过阅读代码,可以发现DOMRenderer是在react-reconciler导出的,
可以非常容易的追踪到DOMRenderer.createContainer的代码
文件地址:
packages/react-reconciler/src/ReactFiberReconciler.js

export function createContainer(
  containerInfo: Container,
  isAsync: boolean,
  hydrate: boolean,
): OpaqueRoot {
  return createFiberRoot(containerInfo, isAsync, hydrate);
}

可以看到代码非常的简单,就是简单的调用来createFiberRoot,
然后去寻找createFiberRoot所在
文件地址:
packages/react-reconciler/src/ReactFiberRoot.js

export function createFiberRoot(
  containerInfo: any,
  isAsync: boolean,
  hydrate: boolean,
): FiberRoot {
  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  // 首先创建hostRoot
  const uninitializedFiber = createHostRootFiber(isAsync);

这里的代码也很简单,首先会去创建createHostRootFiber

暂时先到这里:)

你可能感兴趣的:(React fiber 源码分析1(版本16.6.3))