手记

react源码学习(一)

还处于初级学习阶段,懵懵懂懂,边学习边将自己的理解记录下来,后期随着理解的深入会不断回过头来完善。


ReactDOM.render

ReactDOM.render是渲染组件的第一步,接收三个参数:第一个是createElement创建出来的ReactElement,第二个是dom容器,用来存放ReactElement,第三个是回调函数,用于组件装载后执行的操作。

这个函数做的事情:它会调legacyRenderSubtreeIntoContainer,并将所有参数传给这个函数。然后后面的关键性操作就可以去legacyRenderSubtreeIntoContainer这里面看了。

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


legacyRenderSubtreeIntoContainer

这个函数做的事情:

  1. 看container里有没有_reactRootContainer,我们这里先分析初次进来的情况,初次进来肯定是没有的,所以会去执行legacyCreateRootFromDOMContainer,legacyCreateRootFromDOMContainer里还会调用别的函数,兜兜转转返回一个FiberRoot。

  2. 再往下看,parentComponent传进来的就是null,所以直接执行root.render,即ReactRoot.render这个方法。

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( // 返回一个FiberRoot
          container,
          forceHydrate,
        );
        // Initial mount should not be batched.这里还不懂,后面会学到
        unbatchedUpdates(() => {
          if (parentComponent != null) {
            root.legacy_renderSubtreeIntoContainer(
              parentComponent,
              children,
              callback,
            );
          } else {
            root.render(children, callback);
          }
        });
      }
      return getPublicRootInstance(root._internalRoot);
    }


ReactRoot.render

这个函数做的事情:执行updateContainer

ReactRoot.prototype.render = function(
      children: ReactNodeList,
      callback: ?() => mixed,
    ): Work {
      const root = this._internalRoot;
      const work = new ReactWork();
      callback = callback === undefined ? null : callback;
      if (__DEV__) {
        warnOnInvalidCallback(callback, 'render');
      }
      if (callback !== null) {
        work.then(callback);
      }
      updateContainer(children, root, null, work._onCommit);
      return work;
    };


updateContainer

这个函数做的事情:计算当前时间,超时时间,并传给updateContainerAtExpirationTime

export function updateContainer(
      element: ReactNodeList,
      container: OpaqueRoot,
      parentComponent: ?React$Component<any, any>,
      callback: ?Function,
    ): ExpirationTime {
      const current = container.current;
      const currentTime = requestCurrentTime();
      const expirationTime = computeExpirationForFiber(currentTime, current);
      return updateContainerAtExpirationTime(
        element,
        container,
        parentComponent,
        expirationTime,
        callback,
      );
    }


updateContainerAtExpirationTime

这个函数做的事情:执行scheduleRootUpdate,到这里我已经不明白了。

export function updateContainerAtExpirationTime(
      element: ReactNodeList,
      container: OpaqueRoot,
      parentComponent: ?React$Component<any, any>,
      expirationTime: ExpirationTime,
      callback: ?Function,
    ) {
      // TODO: If this is a nested container, this won't be the root.
      const current = container.current;
      const context = getContextForSubtree(parentComponent);
      if (container.context === null) {
        container.context = context;
      } else {
        container.pendingContext = context;
      }
    
      return scheduleRootUpdate(current, element, expirationTime, callback);
    }


scheduleRootUpdate

从这里开始我也不明白了,总之是调用scheduleWork,开始调度了。

function scheduleRootUpdate(
      current: Fiber,
      element: ReactNodeList,
      expirationTime: ExpirationTime,
      callback: ?Function,
    ) {
      const update = createUpdate(expirationTime);
      // Caution: React DevTools currently depends on this property
      // being called "element".
      update.payload = {element};
    
      callback = callback === undefined ? null : callback;
    
      flushPassiveEffects();
      enqueueUpdate(current, update);
      scheduleWork(current, expirationTime); // 最最最复杂的一块,开始调度
    
      return expirationTime;
    }


1人推荐
随时随地看视频
慕课网APP