react启动流程详解

348 阅读1分钟

const reactDOMRoot = ReactDOM.unstable_createRoot(document.getElementById('root')); 创建一个reactDomRoot

createRoot()--> return new ReactDOMRoot(container, options);

    function ReactDOMRoot(container: Container, options: void | RootOptions) {
    this._internalRoot = createRootImpl(container, ConcurrentRoot /* 2 */, options);// 创建一个fiberRoot对象, 并将其挂载到this._internalRoot之上
  }
function createRootImpl(
container: Container,
tag: RootTag,
options: void | RootOptions,
) {
...服务端相关
const root = createContainer(container, tag, hydrate, hydrationCallbacks); // FiberRoot
markContainerAsRoot(root.current, container); // container['__reactContainer$' + randomKey;] = root.current;
const containerNodeType = container.nodeType;

if (enableEagerRootListeners) {
  const rootContainerElement =
    container.nodeType === COMMENT_NODE/**注释节点 nodetype == 8 */ ? container.parentNode : container;
  listenToAllSupportedEvents(rootContainerElement);// 注册事件监听 多种事件 冒泡捕获,是否可以preventdefault()...
}
...
return root;
}

createContainer()-->createFiberRoot()

export function createFiberRoot(
  containerInfo: any,
  tag: RootTag,
  hydrate: boolean,
  hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
  const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
  if (enableSuspenseCallback) {
    root.hydrationCallbacks = hydrationCallbacks;
  }

  // Cyclic construction. This cheats the type system right now because
  // stateNode is any.
  const uninitializedFiber = createHostRootFiber(tag);//createFiber(HostRoot, null, null, mode); -->new FiberNode(tag, pendingProps, key, mode)
  root.current = uninitializedFiber;
  uninitializedFiber.stateNode = root;

  initializeUpdateQueue(uninitializedFiber); // 初始化updateQueue

  return root;
}

reactDOMRoot.render();

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

updateContainer

  export function updateContainer(
  element: ReactNodeList,
  container: OpaqueRoot,
  parentComponent: ?React$Component<any, any>,
  callback: ?Function,
): Lane {
  if (__DEV__) {
    onScheduleRoot(container, element); // root ,children </ App>  rootElements.set(root, children);
  }
  const current = container.current; //FiberNode
  const eventTime = requestEventTime(); // now()
  ...
  const lane = requestUpdateLane(current);

  if (enableSchedulingProfiler) {
    markRenderScheduled(lane); // performance.mark
  }

  const context = getContextForSubtree(parentComponent); // const emptyContextObject = {};
  if (container.context === null) {
    container.context = context;
  } else {
    container.pendingContext = context;
  }

 ...

  const update = createUpdate(eventTime, lane); //Update
  // Caution: React DevTools currently depends on this property
  // being called "element".
  update.payload = {element}; // element = <App />

  ...
  }

  enqueueUpdate(current, update); // current  HostFiberRoot ==> fiber.updateQueue.shared.pending = update update.next=update
  scheduleUpdateOnFiber(current, lane, eventTime); // schedular入口

  return lane;
}

scheduleUpdateOnFiber

export function scheduleUpdateOnFiber(
  fiber: Fiber,
  lane: Lane,
  eventTime: number,
) {
  ...
  const root = markUpdateLaneFromFiberToRoot(fiber, lane); // fiber.stateNode;
 
  // Mark that the root has a pending update.
  markRootUpdated(root, lane, eventTime);

  ...

  // TODO: requestUpdateLanePriority also reads the priority. Pass the
  // priority as an argument to that function and this one.
  const priorityLevel = getCurrentPriorityLevel();

  if (lane === SyncLane) {
    ...
  } else {
    // Schedule a discrete update but only if it's not Sync.
    ...
    // Schedule other updates after in case the callback is sync.
    ensureRootIsScheduled(root, eventTime); //  root.callbackPriority = newCallbackPriority; root.callbackNode = newCallbackNode -->scheduleCallback;
   ...
  }

 ...
}