美文网首页
React 源码(四)React 模式

React 源码(四)React 模式

作者: bowen_wu | 来源:发表于2021-03-02 11:07 被阅读0次

    概述

    官方文档中有三种模式

    • legacy 模式ReactDOM.render(<App />, rootNode)
    • blocking 模式ReactDOM.createBlockingRoot(rootNode).render(<App />)
    • concurrent 模式ReactDOM.createRoot(rootNode).render(<App />)

    为啥会有三种模式,React 官方文档也给出了相关说明,咱们从源码的上看看三者有何区别

    ReactDOM.createBlockingRoot VS ReactDOM.createRoot

    ReactDOM.createBlockingRoot

    export function createBlockingRoot(container: Container, options?: RootOptions): RootType {
      return new ReactDOMBlockingRoot(container, BlockingRoot, options);
    }
    
    function ReactDOMBlockingRoot(container: Container, tag: RootTag, options: void | RootOptions) {
      this._internalRoot = createRootImpl(container, tag, options);
    }
    

    ReactDOM.createRoot

    export function createRoot(container: Container, options?: RootOptions): RootType {
      return new ReactDOMRoot(container, options);
    }
    
    function ReactDOMRoot(container: Container, options: void | RootOptions) {
      this._internalRoot = createRootImpl(container, ConcurrentRoot, options);
    }
    

    可以从代码中看出,二者都返回一个对象,这个对象中有一个 _internalRoot 属性,属性值为 createRootImpl 的返回值,并且传入 createRootImpl 的第二个参数是不同的,一个是 BlockingRoot 一个是 ConcurrentRoot。在源码中还可以看见 render 方法

    ReactDOMRoot.prototype.render = ReactDOMBlockingRoot.prototype.render = function (children: ReactNodeList): void {
      const root = this._internalRoot;
      updateContainer(children, root, null, null);
    };
    

    也就是说两者最终都调用了 updateContainer 方法

    ReactDOM.render

    export function render(element: React$Element<any>, container: Container, callback: ?Function) {
      return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);
    }
    
    function legacyRenderSubtreeIntoContainer(
      parentComponent: ?React$Component<any, any>,
      children: ReactNodeList, 
      container: Container, 
      forceHydrate: boolean, 
      callback: ?Function
    ) {
      let root: RootType = (container._reactRootContainer: any);
      let fiberRoot;
    
      if (!root) {
        // Initial mount
        root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
        fiberRoot = root._internalRoot;
    
        if (typeof callback === 'function') {
          const originalCallback = callback;
          callback = function () {
            const instance = getPublicRootInstance(fiberRoot);
            originalCallback.call(instance);
          };
        }
    
        // Initial mount should not be batched.
        unbatchedUpdates(() => {
          updateContainer(children, fiberRoot, parentComponent, callback);
        });
      } else {
        fiberRoot = root._internalRoot;
        if (typeof callback === 'function') {
          const originalCallback = callback;
          callback = function () {
            const instance = getPublicRootInstance(fiberRoot);
            originalCallback.call(instance);
          };
        }
        // Update
        updateContainer(children, fiberRoot, parentComponent, callback);
      }
    
      return getPublicRootInstance(fiberRoot);
    }
    
    // legacyCreateRootFromDOMContainer
    function legacyCreateRootFromDOMContainer(container: Container, forceHydrate: boolean): RootType {
      const shouldHydrate = forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
      // First clear any existing content.
      if (!shouldHydrate) {
        let rootSibling;
        while ((rootSibling = container.lastChild)) {
          container.removeChild(rootSibling);
        }
      }
      return createLegacyRoot(container, shouldHydrate ? {hydrate: true} : undefined);
    }
    
    // createLegacyRoot
    export function createLegacyRoot(container: Container, options?: RootOptions): RootType {
      return new ReactDOMBlockingRoot(container, LegacyRoot, options);
    }
    

    从代码中可以看到,render -> legacyRenderSubtreeIntoContainer -> legacyCreateRootFromDOMContainer -> createLegacyRoot -> ReactDOMBlockingRoot,即 renderrootReactDOMBlockingRoot 的实例,但是这里的参数是 LegacyRoot。并且在 legacyRenderSubtreeIntoContainer 函数中也调用了 updateContainer

    三种模式特性对比

    相关文章

      网友评论

          本文标题:React 源码(四)React 模式

          本文链接:https://www.haomeiwen.com/subject/sastqltx.html