react源码解析--笔记

84 阅读3分钟

第一天:解析生成setState的dispatchSetState方法,也就是setState(XX)的时候到底做了什么

function dispatchSetState<S, A>(
  fiber: Fiber,// 当前组件的 Fiber 对象,用于获取组件的相关信息。
  queue: UpdateQueue<S, A>,//状态更新队列(UpdateQueue)对象,用于存储待处理的更新操作。
  action: A, // 表示状态更新的动作 即为setState传入的值 setState(1 || (curState)=>{...curState})的参数 =》 1 或是 (curState)=>{...curState}
): void {
  if (__DEV__) {
    if (typeof arguments[3] === 'function') {
      console.error(
        "State updates from the useState() and useReducer() Hooks don't support the " +
          'second callback argument. To execute a side effect after ' +
          'rendering, declare it in the component body with useEffect().',
      );
    }
  }

  const lane = requestUpdateLane(fiber);//获取更新的调度优先级(lane)

  const update: Update<S, A> = {//创建一个更新对象
    lane,
    revertLane: NoLane,
    action,// 存储状态更新的动作。
    hasEagerState: false,
    eagerState: null,
    next: (null: any),//用于形成更新队列的链表结构
  };

  if (isRenderPhaseUpdate(fiber)) {//根据当前是否处于渲染阶段,将更新操作添加到相应的更新队列中
    enqueueRenderPhaseUpdate(queue, update); // 将更新操作添加到渲染阶段更新队列中,以确保在当前渲染阶段结束后立即处理该更新。
  } else {
    const alternate = fiber.alternate;
    // 检查当前组件的 Fiber 对象的 alternate 属性是否存在。
    // alternate 是指当前组件的上一个渲染结果对应的 Fiber 对象。
    // 如果 alternate 不存在或者 alternate.lanes 为 NoLanes,表示当前组件是首次渲染。
    if (
      fiber.lanes === NoLanes &&
      (alternate === null || alternate.lanes === NoLanes)
    ) {// 当前组件是首次渲染
      // The queue is currently empty, which means we can eagerly compute the
      // next state before entering the render phase. If the new state is the
      // same as the current state, we may be able to bail out entirely.
      // 获取上一次渲染使用的 reducer
      const lastRenderedReducer = queue.lastRenderedReducer;
      if (lastRenderedReducer !== null) {
        let prevDispatcher;
        if (__DEV__) {
          prevDispatcher = ReactCurrentDispatcher.current;
          ReactCurrentDispatcher.current =
            InvalidNestedHooksDispatcherOnUpdateInDEV;
        }
        try {
          const currentState: S = (queue.lastRenderedState: any); //当前未变化的状态
          // 执行该 reducer (useState中即为默认 basicStateReducer =》useState的第一个参数 ),以获取预先计算的状态(eagerState)=》这次变化最新的状态 和当前状态做对比
          const eagerState = lastRenderedReducer(currentState, action); // 也就是这此setState传入的最新状态
          // Stash the eagerly computed state, and the reducer used to compute
          // it, on the update object. If the reducer hasn't changed by the
          // time we enter the render phase, then the eager state can be used
          // without calling the reducer again.
          update.hasEagerState = true;
          update.eagerState = eagerState;
          // 如果预先计算的状态与当前状态相同,说明状态未发生变化,可以直接返回,避免触发 React 的重新渲染。
          // 否则,将预先计算的状态存储在更新对象中,并将更新操作添加到并发更新队列中。
          if (is(eagerState, currentState)) { // !这次变化最新的状态 和当前状态做对比(浅比较) 相等则不往下走不更新
            // Fast path. We can bail out without scheduling React to re-render.
            // It's still possible that we'll need to rebase this update later,
            // if the component re-renders for a different reason and by that
            // time the reducer has changed.
            // TODO: Do we still need to entangle transitions in this case?
            enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update);
            return;
          }
        } catch (error) {
          // Suppress the error. It will throw again in the render phase.
        } finally {
          if (__DEV__) {
            ReactCurrentDispatcher.current = prevDispatcher;
          }
        }
      }
    }
    // 将更新操作添加到并发更新队列中,并返回根 Fiber 对象
    const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
    // 返回的根 Fiber 对象不为空,表示更新队列中的更新操作已经被添加到了调度器中
    if (root !== null) {
      // 安排 React 在适当的时机重新渲染组件。
      scheduleUpdateOnFiber(root, fiber, lane);
      entangleTransitionUpdate(root, queue, lane);
    }
  }
  // 将更新操作标记为开发工具(DevTools)中的更新
  markUpdateInDevTools(fiber, lane, action);
}