zoukankan      html  css  js  c++  java
  • React源码解析——创建更新过程

    一、ReactDOM.render

    创建ReactRoot,并且根据情况调用root.legacy_renderSubtreeIntoContainer或者root.render,前者是遗留的 API 将来应该会删除,根据ReactDOM.render的调用情况也可以发现parentComponent是写死的null

    DOMRenderer.unbatchedUpdates制定不使用batchedUpdates,因为这是初次渲染,需要尽快完成。

      hydrate(element: React$Node, container: DOMContainer, callback: ?Function) {
        // TODO: throw or warn if we couldn't hydrate?
        return legacyRenderSubtreeIntoContainer(
          null,
          element,
          container,
          true,
          callback,
        );
      },
    
      render(
        element: React$Element<any>,
        container: DOMContainer,
        callback: ?Function,
      ) {
        return legacyRenderSubtreeIntoContainer(
          null,
          element,
          container,
          false,
          callback,
        );
      },
    

      

    function legacyRenderSubtreeIntoContainer(
      parentComponent: ?React$Component<any, any>,
      children: ReactNodeList,
      container: DOMContainer,
      forceHydrate: boolean,
      callback: ?Function,
    ) {
      let root: Root = (container._reactRootContainer: any);
      if (!root) {
        // Initial mount
        root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
          container,
          forceHydrate,
        );
        if (typeof callback === 'function') {
          const originalCallback = callback;
          callback = function() {
            const instance = DOMRenderer.getPublicRootInstance(root._internalRoot);
            originalCallback.call(instance);
          };
        }
        // Initial mount should not be batched.
        DOMRenderer.unbatchedUpdates(() => {
          if (parentComponent != null) {
            root.legacy_renderSubtreeIntoContainer(
              parentComponent,
              children,
              callback,
            );
          } else {
            root.render(children, callback);
          }
        });
      } else {
        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);
        }
      }
      return DOMRenderer.getPublicRootInstance(root._internalRoot);
    }
    

    首先会创建ReactRoot对象,然后调用他的render方法

    创建ReactRoot的时候会调用DOMRenderer.createContainer创建FiberRoot,在后期调度更新的过程中这个节点非常重要

    function legacyCreateRootFromDOMContainer(
      container: DOMContainer,
      forceHydrate: boolean,
    ): Root {
      const shouldHydrate =
        forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
      // First clear any existing content.
      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 isConcurrent = false;
      return new ReactRoot(container, isConcurrent, shouldHydrate);
    }
    

      

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

      

    二、启动调度

    首先要生成一个update,不管你是setState还是ReactDOM.render造成的 React 更新,都会生成一个叫update的对象,并且会赋值给Fiber.updateQueue

    然后就是调用scheduleWork。注意到这里之前setStateReactDOM.render是不一样,但进入schedulerWork之后,就是任务调度的事情了,跟之前你是怎么调用的没有任何关系

    function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
      const root = scheduleWorkToRoot(fiber, expirationTime);
      if (root === null) {
        return;
      }
    
      if (
        !isWorking &&
        nextRenderExpirationTime !== NoWork &&
        expirationTime < nextRenderExpirationTime
      ) {
        // This is an interruption. (Used for performance tracking.)
        interruptedBy = fiber;
        resetStack();
      }
      markPendingPriorityLevel(root, expirationTime);
      if (
        // If we're in the render phase, we don't need to schedule this root
        // for an update, because we'll do it before we exit...
        !isWorking ||
        isCommitting ||
        // ...unless this is a different root than the one we're rendering.
        nextRoot !== root
      ) {
        const rootExpirationTime = root.expirationTime;
        requestWork(root, rootExpirationTime);
      }
      if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
        // Reset this back to zero so subsequent updates don't throw.
        nestedUpdateCount = 0;
        invariant(
          false,
          'Maximum update depth exceeded. This can happen when a ' +
            'component repeatedly calls setState inside ' +
            'componentWillUpdate or componentDidUpdate. React limits ' +
            'the number of nested updates to prevent infinite loops.',
        );
      }
    }
    

      

      

  • 相关阅读:
    爱情十二课,失恋后遗症
    爱情十三课,爱人的五功能
    爱情第八课,爱也是投资
    爱情第二课,择爱两大误区
    爱情十七课,吵架的原则
    MFC DC的获取
    MFC关于使用CArchive流输入产生的问题
    MFCCFileException类学习笔记
    MFC中指针的获取
    文字编辑和文字处理
  • 原文地址:https://www.cnblogs.com/fuGuy/p/11711059.html
Copyright © 2011-2022 走看看