React fiber 源码分析2(版本16 6 3)

273 阅读2分钟

上一篇讲到了createFiberRoot

function createFiberRoot(containerInfo, isConcurrent, hydrate) {
  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  // 首先创建hostroot
  var uninitializedFiber = createHostRootFiber(isConcurrent);

  var root = void 0;
  // 跟踪
  // Trace which interactions trigger each commit.
  // var enableSchedulerTracing = true;

  if (enableSchedulerTracing) {
    root = {
      // 指向了刚才创建的HostRoot
      current: uninitializedFiber,
      // container信息
      containerInfo: containerInfo,
      pendingChildren: null,

      earliestPendingTime: NoWork,
      latestPendingTime: NoWork,
      earliestSuspendedTime: NoWork,
      latestSuspendedTime: NoWork,
      latestPingedTime: NoWork,

      didError: false,
      // NoWork 0
      pendingCommitExpirationTime: NoWork,
      finishedWork: null,
      timeoutHandle: noTimeout,
      context: null,
      pendingContext: null,
      hydrate: hydrate,
      nextExpirationTimeToWorkOn: NoWork,
      expirationTime: NoWork,
      firstBatch: null,
      nextScheduledRoot: null,
      // threadIDCounter初始值0
      // function unstable_getThreadID() {
      //   return ++threadIDCounter;
      // }
      interactionThreadID: tracing.unstable_getThreadID(),
      memoizedInteractions: new Set(),
      pendingInteractionMap: new Map()
    };
  } else {
    root = {
      current: uninitializedFiber,
      containerInfo: containerInfo,
      pendingChildren: null,

      earliestPendingTime: NoWork,
      latestPendingTime: NoWork,
      earliestSuspendedTime: NoWork,
      latestSuspendedTime: NoWork,
      latestPingedTime: NoWork,

      didError: false,

      pendingCommitExpirationTime: NoWork,
      finishedWork: null,
      timeoutHandle: noTimeout,
      context: null,
      pendingContext: null,
      hydrate: hydrate,
      nextExpirationTimeToWorkOn: NoWork,
      expirationTime: NoWork,
      firstBatch: null,
      nextScheduledRoot: null
    };
  }

  uninitializedFiber.stateNode = root;

  // The reason for the way the Flow types are structured in this file,
  // Is to avoid needing :any casts everywhere interaction tracing fields are used.
  // Unfortunately that requires an :any cast for non-interaction tracing capable builds.
  // $FlowFixMe Remove this :any cast and replace it with something better.
  return root;
}

函数也很简单,就是形成了一个root.current = HostRoot, HostRoot.stateNode = root

#createHostRootFiber

// isConcurrent false
function createHostRootFiber(isConcurrent) {
  // var NoContext = 0;
  // var ConcurrentMode = 1;
  // var StrictMode = 2;
  // ProfileMode =3
  var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext;

  if (enableProfilerTimer && isDevToolsPresent) {
    // Always collect profile timings when DevTools are present.
    // This enables DevTools to start capturing timing at any point–
    // Without some nodes in the tree having empty base times.
    mode |= ProfileMode;
  }
  // HostRoot = 3
  // mode = 4
  return createFiber(HostRoot, null, null, mode);
}

这里很简单,就是直接到了createFiber

createFiber

// This is a constructor function, rather than a POJO constructor, still
// please ensure we do the following:
// 1) Nobody should add any instance methods on this. Instance methods can be
//    more difficult to predict when they get optimized and they are almost
//    never inlined properly in static compilers.
// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
//    always know when it is a fiber.
// 3) We might want to experiment with using numeric keys since they are easier
//    to optimize in a non-JIT environment.
// 4) We can easily go from a constructor to a createFiber object literal if that
//    is faster.
// 5) It should be easy to port this to a C struct and keep a C implementation
//    compatible.
var createFiber = function (tag, pendingProps, key, mode) {
  // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
  return new FiberNode(tag, pendingProps, key, mode);
};

也很简单,就是一个返回FiberNode对象。 #FiberNode

function FiberNode(tag, pendingProps, key, mode) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.elementType = null;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this.return = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  this.ref = null;

  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;
  this.firstContextDependency = null;

  this.mode = mode;

  // Effects
  this.effectTag = NoEffect;
  this.nextEffect = null;

  this.firstEffect = null;
  this.lastEffect = null;

  this.expirationTime = NoWork;
  this.childExpirationTime = NoWork;

  this.alternate = null;

  if (enableProfilerTimer) {
    this.actualDuration = 0;
    this.actualStartTime = -1;
    this.selfBaseDuration = 0;
    this.treeBaseDuration = 0;
  }

  {
    this._debugID = debugCounter++;
    this._debugSource = null;
    this._debugOwner = null;
    this._debugIsCurrentlyTiming = false;
    if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
      Object.preventExtensions(this);
    }
  }
}

就是一个对象,有各种各种的属性。 可以看下最后创建的HostRoot对象,如下图所示:

image.png
经历完这些之后,就又回到了legacyRenderSubtreeIntoContainer 经过一系列的调用调用之后

function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
 // TODO: Ensure all entry points contain this check
 !isValidContainer(container) ? invariant(false, 'Target container is not a DOM element.') : void 0;

 {
   topLevelUpdateWarnings(container);
 }

 // TODO: Without `any` type, Flow says "Property cannot be accessed on any
 // member of intersection type." Whyyyyyy.
 var root = container._reactRootContainer;
 if (!root) {
   // Initial mount
   // root._internalRoot 就是在刚才创建的root对象,
   root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
   // callback null
   if (typeof callback === 'function') {
     var originalCallback = callback;
     callback = function () {
       var instance = getPublicRootInstance(root._internalRoot);
       originalCallback.call(instance);
     };
   }
   // Initial mount should not be batched.
   // 初次渲染的时候,
   unbatchedUpdates(function () {
     if (parentComponent != null) {
       root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
     } else {
       // container完成之后,渲染子组件
       root.render(children, callback);
     }
   });
 } else {
   if (typeof callback === 'function') {
     var _originalCallback = callback;
     callback = function () {
       var instance = getPublicRootInstance(root._internalRoot);
       _originalCallback.call(instance);
     };
   }
   // Update
   if (parentComponent != null) {
     root.legacy_renderSubtreeIntoContainer(parentComponent, children, callback);
   } else {
     root.render(children, callback);
   }
 }
 return getPublicRootInstance(root._internalRoot);
}

然后就会执行

ReactRoot.prototype.render = function (children, callback) {
 // 就是创建的root对象
 var root = this._internalRoot;
 // 创建reactwork
 var work = new ReactWork();
 callback = callback === undefined ? null : callback;
 {
   warnOnInvalidCallback(callback, 'render');
 }
 if (callback !== null) {
   work.then(callback);
 }
 // 更新container
 updateContainer(children, root, null, work._onCommit);
 return work;
};