React19源码系列之Hooks(useState)

发布于:2025-06-16 ⋅ 阅读:(15) ⋅ 点赞:(0)

useState的使用

1、简单基础用法:

import React, { useState } from 'react';

function Counter() {
  // 声明一个名为 count 的状态变量,初始值为 0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={() => setCount(prev => prev - 1)}>Decrement</button>
    </div>
  );
}

2、当初始值需要通过复杂计算获得时,可以传入一个函数: 

function ExpensiveComponent() {
  // 只会在组件初始化时执行一次
  const [data, setData] = useState(() => {
    return expensiveComputation(); // 复杂计算
  });
  
  // ...
}

 3、对于对象或数组状态,需要更新部分值:

function Form() {
  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });

  const handleChange = (e) => {
    // 合并更新部分字段
    setFormData(prev => ({
      ...prev,
      [e.target.name]: e.target.value
    }));
  };
  
  // ...
}

useState执行的流程图

初始化入口

useState 函数是 React 中用于在函数组件中添加状态的重要 Hook。它的主要作用是为函数组件引入状态管理能力,允许组件在渲染过程中拥有和更新状态值。该函数接收一个初始状态值(可以是一个值或者一个返回值的函数),并返回一个包含当前状态值和用于更新状态的调度函数的数组。

function useState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  // 调用 resolveDispatcher 函数来获取当前的调度器实例。在 React 的架构中,调度器负责管理组件的更新、渲染等操作。resolveDispatcher 函数会根据当前的上下文环境(例如,是否处于渲染阶段、是否在服务器端渲染等)来确定并返回正确的调度器实例。
  const dispatcher = resolveDispatcher();
  
  // 调用调度器的 useState 方法
  return dispatcher.useState(initialState);
}

initialState 可以是两种形式:

  • 直接传入一个具体的状态值,例如 useState(0),此时初始状态就是 0
  • 传入一个函数,例如 useState(() => []),在这种情况下,只有在组件首次渲染时才会调用这个函数,函数的返回值将作为初始状态。这样做的好处是可以避免在每次渲染时都重新计算初始状态(因为函数组件在每次更新时都会重新执行)。

resolveDispatcher 函数的主要作用是解析并返回当前 React 环境中的调度器(dispatcher)。调度器在 React 中扮演着至关重要的角色,它负责管理组件的更新、渲染调度等任务,确保 React 应用能够高效、有序地运行。


function resolveDispatcher() {
  // 从 ReactSharedInternals 对象中获取名为 H 的属性,并将其赋值给变量 dispatcher。ReactSharedInternals 是 React 内部使用的一个共享对象,它包含了一些 React 运行时的关键信息和工具。H 属性在这里代表着当前 React 环境下的调度器实例。
  const dispatcher = ReactSharedInternals.H;
  // 将获取到的调度器实例 dispatcher 返回给调用者。这样,调用 resolveDispatcher 函数的代码就可以使用这个调度器来执行各种调度相关的操作,比如调用调度器的 useState 方法来处理状态管理。
  return dispatcher;
}

useState(initialState) {
  // 在开发环境中,将当前正在使用的钩子名称设置为 'useState'。
  currentHookNameInDev = 'useState';

  // 调用 mountHookTypesDev 函数,这个函数可能用于记录和管理当前组件中使用的钩子类型,同样是为了开发调试时能更好地跟踪和分析钩子的使用情况。
  // mountHookTypesDev();

  // 保存当前的调度器实例到 prevDispatcher 变量中。ReactSharedInternals.H 是 React 内部用于存储调度器的属性。
  const prevDispatcher = ReactSharedInternals.H;
  // 调度器替换为 InvalidNestedHooksDispatcherOnMountInDEV。这是为了在开发环境中防止在 useState 挂载过程中出现嵌套钩子调用的错误。如果在这个过程中错误地调用了其他钩子,会触发相应的错误提示。
  ReactSharedInternals.H = InvalidNestedHooksDispatcherOnMountInDEV;

  try {
    return mountState(initialState);
  } finally {
    // ReactSharedInternals.H = prevDispatcher;
  }
},

mountState(初始化)

mountState 函数是 React 中用于在组件挂载阶段初始化 useState 钩子的核心函数。useState 是 React 函数式组件中用于管理状态的重要钩子,mountState 函数的主要任务是创建并初始化状态钩子,为状态管理提供必要的基础设施,包括创建状态钩子实例、设置状态更新队列和返回状态值及更新状态的方法。

函数参数含义:

  • initialState:初始状态值,可以是状态的具体值,也可以是一个返回状态值的函数。如果传入的是函数,React 会在初始化状态时调用该函数并使用其返回值作为初始状态。
function mountState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {

  // 创建并初始化状态钩子实例。它会根据传入的 initialState 初始化状态,并将其存储在钩子的 memoizedState 属性中。hook 对象包含了状态钩子的相关信息,如当前状态值、更新队列等。
  const hook = mountStateImpl(initialState);
  
  // 获取状态更新队列,用于存储待处理的状态更新操作。在 React 中,状态更新并不是立即生效的,而是会被收集到更新队列中,在合适的时机统一处理。
  const queue = hook.queue;

   // 创建状态更新函数
  const dispatch: Dispatch<BasicStateAction<S>> = (dispatchSetState.bind(
    null,
    currentlyRenderingFiber, // 当前渲染到fiber
    queue,// 更新队列
  ): any);

  // 将创建好的 dispatch 函数赋值给 queue 的 dispatch 属性,这样在后续处理更新队列时,可以通过 queue.dispatch 调用该函数。
  queue.dispatch = dispatch;
  
  return [hook.memoizedState, dispatch];
}

hook钩子对象结构: 

初始化流程图:

mountStateImpl

mountStateImpl 函数是 React 内部用于在函数组件挂载时初始化状态的关键函数,它是 useState 底层实现的一部分。其核心功能包括创建新的 Hook 实例、处理初始状态(如果初始状态是函数则执行它)、初始化 Hook 的状态属性,并且为 Hook 配置一个更新队列,最后返回初始化好的 Hook

function mountStateImpl<S>(initialState: (() => S) | S): Hook {
  // 创建hook实例
  const hook = mountWorkInProgressHook();
  
  if (typeof initialState === 'function') {
    const initialStateInitializer = initialState;
    // 计算获得初始值
    initialState = initialStateInitializer();
  }
  // 初始化 Hook 的状态属性
  hook.memoizedState = hook.baseState = initialState;

  // 创建更新队列
  const queue: UpdateQueue<S, BasicStateAction<S>> = {
    pending: null,// 用于存储待处理的更新操作,初始值为 null。
    lanes: NoLanes, // 表示更新的优先级车道,初始值为 NoLanes,即没有指定优先级。
    dispatch: null,// 用于触发状态更新的函数,初始值为 null
    
    // 最后一次渲染时使用的状态更新函数,这里初始化为 basicStateReducer。
    lastRenderedReducer: basicStateReducer,
    
    // 最后一次渲染时的状态值,初始化为 initialState。
    lastRenderedState: (initialState: any),
  };

  // 关联到hook链表
  hook.queue = queue;
  
  return hook;
}

dispatchSetState

dispatchSetState 函数是 React 中处理 setState 操作的关键函数之一。它的主要作用是为 setState 操作分配一个更新优先级车道(lane),然后调用内部函数 dispatchSetStateInternal 来处理更新的调度,并且在成功调度更新的情况下,启动一个更新定时器。

函数参数含义:

  • fiber:当前的 Fiber 节点。Fiber 是 React 16 及以后版本中引入的协调算法的基础数据结构,代表了组件树中的一个节点。
  • queue:更新队列,用于存储 setState 操作的相关信息。每个 Fiber 节点都有一个对应的更新队列,用于管理该节点的状态更新。
  • actionsetState 操作传入的动作,通常是一个对象或函数。例如,setState({ count: 1 }) 中的 { count: 1 } 就是一个动作对象;setState(prevState => ({ count: prevState.count + 1 })) 中的 prevState => ({ count: prevState.count + 1 }) 就是一个动作函数。
function dispatchSetState<S, A>(
  fiber: Fiber,
  queue: UpdateQueue<S, A>,
  action: A,
): void {

  // 分配更新优先级车道
  const lane = requestUpdateLane(fiber);

  //调度更新
  const didScheduleUpdate = dispatchSetStateInternal(
    fiber,// 当前的 Fiber 节点
    queue,// queue(更新队列,用于存储 setState 操作的相关信息)
    action,// action(setState 操作传入的动作,通常是一个对象或函数)
    lane,// 更新优先级车道
  );
  // 检查 didScheduleUpdate 的值,如果为 true,说明更新成功调度。
  if (didScheduleUpdate) {
    // startUpdateTimerByLane 函数的作用是根据车道的优先级启动一个更新定时器,用于在合适的时间触发更新操作,以确保更新能够按照优先级顺序进行处理。
    // 启动更新定时器
    startUpdateTimerByLane(lane);
  }
  // markUpdateInDevTools(fiber, lane, action);
}

dispatchSetStateInternal

dispatchSetStateInternal 函数是 React 中处理 setState 操作的内部核心函数,它的主要任务是将状态更新请求(action)封装成一个 Update 对象,并根据不同情况处理这个更新请求,包括在渲染阶段处理更新、尝试提前计算新状态以避免不必要的更新,以及将更新加入队列并调度更新等操作。最后返回一个布尔值,表示是否成功调度了更新。

函数参数含义:

  • fiber:当前执行更新操作的 Fiber 节点。Fiber 是 React 协调算法的基础数据结构,包含了组件的状态、属性等信息。
  • queue:更新队列,存储了与 setState 操作相关的信息,如之前的状态、reducer 函数等。
  • actionsetState 操作传入的动作,通常是一个值或函数,用于更新状态。
  • lane:更新的优先级车道,用于确定更新的执行顺序,不同的车道对应不同的优先级。
function dispatchSetStateInternal<S, A>(
  fiber: Fiber,
  queue: UpdateQueue<S, A>,
  action: A,
  lane: Lane,
): boolean {
  
  // 创建一个更新对象
  const update: Update<S, A> = {
    lane,// 更新的优先级车道,用于确定更新的执行顺序。
    revertLane: NoLane,// 回滚车道,初始值为 NoLane。
    action,// 状态更新的动作,通常是一个值或函数。
    hasEagerState: false,// 标记是否已经提前计算出了新状态,初始值为 false。
    eagerState: null,// 提前计算出的新状态值,初始值为 null。
    next: (null: any),// 用于将多个 Update 对象连接成一个链表,初始值为 null。
  };

  // 调用 isRenderPhaseUpdate 函数判断当前是否处于渲染阶段。
  if (isRenderPhaseUpdate(fiber)) {
    // 调用 enqueueRenderPhaseUpdate 函数将更新对象添加到渲染阶段的更新队列中。
    enqueueRenderPhaseUpdate(queue, update);
  } else {
    const alternate = fiber.alternate;
    if (
      fiber.lanes === NoLanes &&
      (alternate === null || alternate.lanes === NoLanes)
    ) {
     
      const lastRenderedReducer = queue.lastRenderedReducer;

      // 需要提前计算新状态
      if (lastRenderedReducer !== null) {
        let prevDispatcher = null;

        try {
          const currentState: S = (queue.lastRenderedState: any);
          const eagerState = lastRenderedReducer(currentState, action);
       
          update.hasEagerState = true;
          update.eagerState = eagerState;

          // 如果新状态 eagerState 和当前状态 currentState 相等
          // 表示不需要更新
          if (is(eagerState, currentState)) {
            enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update);
            return false;
          }
        } 
      }
    }

    // 将更新对象添加到并发更新队列中,并获取相关的 FiberRoot。
    const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
    if (root !== null) {
      // 调度更新
      scheduleUpdateOnFiber(root, fiber, lane);

      // 处理过渡更新
      entangleTransitionUpdate(root, queue, lane);
      return true;
    }
  }
  return false;
}

工具函数之 isRenderPhaseUpdate

isRenderPhaseUpdate 函数的主要作用是判断当前的 Fiber 节点是否处于渲染阶段。通过检查 Fiber 节点及其备用 Fiber 节点(alternate)是否与当前正在渲染的 Fiber 节点一致,来确定该 Fiber 节点的更新是否发生在渲染阶段。

function isRenderPhaseUpdate(fiber: Fiber): boolean {
  const alternate = fiber.alternate;
  return (
    fiber === currentlyRenderingFiber ||
    (alternate !== null && alternate === currentlyRenderingFiber)
  );
}

enqueueRenderPhaseUpdate

enqueueRenderPhaseUpdate 函数的主要作用是处理渲染阶段的更新操作。在 React 中,当更新发生在渲染阶段时,会调用这个函数将更新操作暂存到一个更新队列中,以便在当前渲染阶段结束后,重新启动渲染并应用这些暂存的更新到正在处理的 Hook 上。

函数参数含义:

  • queue:类型为 UpdateQueue<S, A>,表示 Hook 的更新队列,用于存储与状态更新相关的信息,包括之前的状态、更新的动作等。
  • update:类型为 Update<S, A>,代表具体的更新操作对象,包含了更新的优先级车道(lane)、回滚车道(revertLane)、更新动作(action)、是否有提前计算的状态(hasEagerState)以及提前计算的状态值(eagerState)等信息。
function enqueueRenderPhaseUpdate<S, A>(
  queue: UpdateQueue<S, A>,
  update: Update<S, A>,
): void {
  
  // 用于记录在当前渲染阶段已经调度了渲染阶段的更新操作
  didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate =
    true;

  // 循环链表
  const pending = queue.pending;
  if (pending === null) {
    // This is the first update. Create a circular list.
    update.next = update;
  } else {
    update.next = pending.next;
    pending.next = update;
  }

 // update 成为队列中当前待处理的更新。
  queue.pending = update;
}

enqueueConcurrentHookUpdateAndEagerlyBailout

React 中处理 并发 Hook 更新 的特殊优化路径,主要用于 跳过优先级调度立即处理更新

function enqueueConcurrentHookUpdateAndEagerlyBailout<S, A>(
  fiber: Fiber,
  queue: HookQueue<S, A>,
  update: HookUpdate<S, A>,
): void {

  const lane = NoLane;
  const concurrentQueue: ConcurrentQueue = (queue: any);
  const concurrentUpdate: ConcurrentUpdate = (update: any);

  enqueueUpdate(fiber, concurrentQueue, concurrentUpdate, lane);

  const isConcurrentlyRendering = getWorkInProgressRoot() !== null;
  if (!isConcurrentlyRendering) {
    finishQueueingConcurrentUpdates();
  }
}
function enqueueUpdate(
  fiber: Fiber,
  queue: ConcurrentQueue | null,
  update: ConcurrentUpdate | null,
  lane: Lane,
) {
  // Don't update the `childLanes` on the return path yet. If we already in
  // the middle of rendering, wait until after it has completed.
  concurrentQueues[concurrentQueuesIndex++] = fiber;
  concurrentQueues[concurrentQueuesIndex++] = queue;
  concurrentQueues[concurrentQueuesIndex++] = update;
  concurrentQueues[concurrentQueuesIndex++] = lane;

  concurrentlyUpdatedLanes = mergeLanes(concurrentlyUpdatedLanes, lane);

  // The fiber's `lane` field is used in some places to check if any work is
  // scheduled, to perform an eager bailout, so we need to update it immediately.
  // TODO: We should probably move this to the "shared" queue instead.
  fiber.lanes = mergeLanes(fiber.lanes, lane);
  const alternate = fiber.alternate;
  if (alternate !== null) {
    alternate.lanes = mergeLanes(alternate.lanes, lane);
  }
}

工具函数之 finishQueueingConcurrentUpdates

React 并发更新机制中 完成更新队列处理 的核心函数,主要负责 将暂存的更新合并到队列标记优先级

function finishQueueingConcurrentUpdates(): void {

  const endIndex = concurrentQueuesIndex;
    // 重置全局变量
  concurrentQueuesIndex = 0;
  concurrentlyUpdatedLanes = NoLanes;

  let i = 0;
  while (i < endIndex) {
    const fiber: Fiber = concurrentQueues[i];
    // 将元素置为 null,释放内存。
    concurrentQueues[i++] = null;
    const queue: ConcurrentQueue = concurrentQueues[i];
    concurrentQueues[i++] = null;
    const update: ConcurrentUpdate = concurrentQueues[i];
    concurrentQueues[i++] = null;
    const lane: Lane = concurrentQueues[i];
    concurrentQueues[i++] = null;

    // 构建循环链表
    if (queue !== null && update !== null) {
      const pending = queue.pending;
      if (pending === null) {
        // This is the first update. Create a circular list.
        update.next = update;
      } else {
        update.next = pending.next;
        pending.next = update;
      }
      queue.pending = update;
    }

    if (lane !== NoLane) {
      // 标记优先级
      markUpdateLaneFromFiberToRoot(fiber, update, lane);
    }
  }
}

enqueueConcurrentHookUpdate

enqueueConcurrentHookUpdate 函数主要用于将一个并发的 Hook 更新操作加入到更新队列中,并且返回更新所关联的 FiberRoot

函数参数含义

  • fiber:当前执行更新操作的 Fiber 节点。
  • queueHook 的更新队列,类型为 HookQueue<S, A>,其中 S 表示状态的类型,A 表示动作(action)的类型。更新队列用于存储一系列的更新操作。
  • update:具体的 Hook 更新操作,类型为 HookUpdate<S, A>,包含了更新所需的信息,如更新的动作、优先级等。
  • lane:更新的优先级车道(Lane)。在 React 的调度系统中,不同的更新会被分配到不同的车道,车道决定了更新的优先级,高优先级的车道会优先被处理。
function enqueueConcurrentHookUpdate<S, A>(
  fiber: Fiber,
  queue: HookQueue<S, A>,
  update: HookUpdate<S, A>,
  lane: Lane,
): FiberRoot | null {

  // 类型转换
  const concurrentQueue: ConcurrentQueue = (queue: any);
  const concurrentUpdate: ConcurrentUpdate = (update: any);

  // 加入更新队列
  enqueueUpdate(
    fiber, 
    concurrentQueue, // 更新队列
    concurrentUpdate, // 具体的更新操作
    lane
  );

  // 返回关联的 FiberRoot
  return getRootForUpdatedFiber(fiber);
}

工具函数之 enqueueUpdate

React 更新队列管理的核心函数,主要处理 更新入队优先级标记

function enqueueUpdate<State>(
  fiber: Fiber,
  update: Update<State>,
  lane: Lane,
): FiberRoot | null {
  
  const updateQueue = fiber.updateQueue;
  if (updateQueue === null) {
    // Only occurs if the fiber has been unmounted.
    return null;
  }

  const sharedQueue: SharedQueue<State> = (updateQueue: any).shared;

  if (isUnsafeClassRenderPhaseUpdate(fiber)) {
    // This is an unsafe render phase update. Add directly to the update
    // queue so we can process it immediately during the current render.
    const pending = sharedQueue.pending;
    
    if (pending === null) {
      // 创建循环链表
      // This is the first update. Create a circular list.
      update.next = update;
    } else {
      // 插入到链表末尾
      update.next = pending.next;
      pending.next = update;
    }
    sharedQueue.pending = update;

    // unsafe_markUpdateLaneFromFiberToRoot 将 lane 标记到根节点,触发同步渲染。
    return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane);
  } else {

    // 1. 处理交错更新(interleaved)
  // 2. 将更新添加到 pending 队列
  // 3. 标记优先级到根节点
  // 4. 返回根节点,触发调度
    return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane);
  }
}
const concurrentQueues: Array<any> = [];
let concurrentQueuesIndex = 0;

let concurrentlyUpdatedLanes: Lanes = NoLanes;
concurrentQueues = [
  fiber1, queue1, update1, lane1,
  fiber2, queue2, update2, lane2,
  // ...
];

工具函数之 isUnsafeClassRenderPhaseUpdate

React 用于 检测不安全的类组件渲染阶段更新 的辅助函数,主要用于 开发模式下的警告提示

function isUnsafeClassRenderPhaseUpdate(fiber: Fiber): boolean {
  return (executionContext & RenderContext) !== NoContext;
}

工具函数之 unsafe_markUpdateLaneFromFiberToRoot

React 中用于 标记更新优先级 的核心函数,主要在 同步更新 场景下使用。

function unsafe_markUpdateLaneFromFiberToRoot(
  sourceFiber: Fiber,
  lane: Lane,
): FiberRoot | null {
  const root = getRootForUpdatedFiber(sourceFiber);
  markUpdateLaneFromFiberToRoot(sourceFiber, null, lane);
  return root;
}

工具函数之 markUpdateLaneFromFiberToRoot

React 中用于标记更新优先级并在 Fiber 树中传播的核心函数,主要作用是将更新的优先级从当前 Fiber 节点向上传播到根节点,确保整个更新流程的优先级管理。

function markUpdateLaneFromFiberToRoot(
  sourceFiber: Fiber,
  update: ConcurrentUpdate | null,
  lane: Lane,
): void {
  // Update the source fiber's lanes
   // 1. 标记当前 Fiber 的 lanes
  sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);

   // 2. 标记双缓存 Fiber 的 lanes
  let alternate = sourceFiber.alternate;
  if (alternate !== null) {
    alternate.lanes = mergeLanes(alternate.lanes, lane);
  }
  // Walk the parent path to the root and update the child lanes.
  let isHidden = false;

  // 3. 向上遍历父节点,标记 childLanes
  let parent = sourceFiber.return;
  let node = sourceFiber;
  
  while (parent !== null) {
    parent.childLanes = mergeLanes(parent.childLanes, lane);
    alternate = parent.alternate;
    
    if (alternate !== null) {
      alternate.childLanes = mergeLanes(alternate.childLanes, lane);
    }

    // 检测离屏组件
    if (parent.tag === OffscreenComponent) {
      const offscreenInstance: OffscreenInstance | null = parent.stateNode;
      if (
        offscreenInstance !== null &&
        !(offscreenInstance._visibility & OffscreenVisible)
      ) {
        // 若父节点是离屏组件且不可见,标记isHidden为true。
        isHidden = true;
      }
    }

    node = parent;
    parent = parent.return;
  }

  // 处理隐藏更新
  if (isHidden && update !== null && node.tag === HostRoot) {
    const root: FiberRoot = node.stateNode;
    // 将更新标记为隐藏状态
    markHiddenUpdate(root, update, lane);
  }
}

工具函数之 markHiddenUpdate

React 中处理 隐藏更新(Hidden Updates) 的核心函数,主要用于 暂存离屏组件的更新,避免不必要的渲染。

 function markHiddenUpdate(
  root: FiberRoot,
  update: ConcurrentUpdate,
  lane: Lane,
) {
   // 按优先级索引存储更新
  const index = laneToIndex(lane);
  const hiddenUpdates = root.hiddenUpdates;
   
  const hiddenUpdatesForLane = hiddenUpdates[index];
   
  if (hiddenUpdatesForLane === null) {
    hiddenUpdates[index] = [update];
  } else {
    hiddenUpdatesForLane.push(update);
  }
   
   // update.lane 同时包含原始优先级和离屏标记。
  update.lane = lane | OffscreenLane;
}
root.hiddenUpdates = [
  [/* 优先级0的更新数组 */],
  [/* 优先级1的更新数组 */],
  // ...
];
function laneToIndex(lane: Lane) {
  return pickArbitraryLaneIndex(lane);
}

updateState(更新入口)

updateState 函数是 React 内部用于更新状态的函数,它本质上是对 updateReducer 函数的封装。该函数借助 basicStateReducer 这个基础的状态归约函数,以一种更简洁的方式实现状态更新逻辑,其功能与 useState 类似,旨在为函数组件提供状态管理能力。

function updateState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  return updateReducer(basicStateReducer, initialState);
}

工具函数之 basicStateReducer

basicStateReducer 是 React 中用于处理状态更新的基础归约函数,通常在 useState 钩子的内部实现里被使用。它接收当前状态 state 和一个动作 action 作为参数,根据 action 的类型来决定如何更新状态,并返回更新后的状态。

function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
  return typeof action === 'function' ? action(state) : action;
}
function updateReducer<S, I, A>(
  reducer: (S, A) => S,
  initialArg: I,// 初始值
  init?: I => S,
): [S, Dispatch<A>] {
  // 获取正在工作的 Hook
  const hook = updateWorkInProgressHook();

  // 调用 updateReducerImpl 函数处理状态更新
  return updateReducerImpl(hook, ((currentHook: any): Hook), reducer);
}

updateReducerImpl

updateReducerImpl 函数是 React 中用于处理 useReducer 钩子状态更新的核心函数。它的主要任务是根据传入的 reducer 函数,处理 Hook 对象中的更新队列,计算出新的状态,并更新 Hook 和相关队列的属性。最终,该函数返回一个包含新状态和状态更新调度函数的数组。

function updateReducerImpl<S, A>(
  hook: Hook,// hook:即前面获取到的当前正在处理的 Hook 对象。
  current: Hook,
  reducer: (S, A) => S,
): [S, Dispatch<A>] {

  // 从 hook 对象中获取更新队列 queue。
  const queue = hook.queue;

  // 将 queue 的 lastRenderedReducer 属性设置为传入的 reducer 函数,记录最后一次使用的 reducer。
  queue.lastRenderedReducer = reducer;

  // 获取 hook 的基础队列 baseQueue 和待处理队列 pendingQueue。
  let baseQueue = hook.baseQueue;
  const pendingQueue = queue.pending;

   // 若 pendingQueue 不为 null,说明有新的更新未处理
  if (pendingQueue !== null) {
    if (baseQueue !== null) {
     // 若 baseQueue 不为 null,则将两个队列连接成一个循环链表。
      const baseFirst = baseQueue.next;
      const pendingFirst = pendingQueue.next;
      baseQueue.next = pendingFirst;
      pendingQueue.next = baseFirst;
    }
    current.baseQueue = baseQueue = pendingQueue;
    queue.pending = null;
  }

  const baseState = hook.baseState;
  
  if (baseQueue === null) {
    hook.memoizedState = baseState;
  } else {
    // 基础队列
    // We have a queue to process.
    const first = baseQueue.next;
    
    let newState = baseState;// 新状态
    let newBaseState = null;// 新基础状态
    let newBaseQueueFirst = null;// 新基础队列首节点
    let newBaseQueueLast: Update<S, A> | null = null;// 新基础队列尾节点
    let update = first;
    let didReadFromEntangledAsyncAction = false;
    
    do {
// removeLanes是一个函数,其作用是从update.lane(当前更新的车道)中移除OffscreenLane。
//在 React 的调度系统里,车道代表着更新的优先级,OffscreenLane 可能表示与屏幕外元素相关的更新优先级。
      const updateLane = removeLanes(update.lane, OffscreenLane);

      // 若 updateLane 与 update.lane 不同,就表明原始的更新车道里包含 OffscreenLane,此更新为隐藏更新,反之,则不是隐藏更新。
      const isHiddenUpdate = updateLane !== update.lane;
      
      // 根据是否为隐藏更新来决定是否应跳过当前更新。
      const shouldSkipUpdate = isHiddenUpdate
        // getWorkInProgressRootRenderLanes() 会返回当前正在处理的根节点的渲染车道
        ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane)
        : !isSubsetOfLanes(renderLanes, updateLane);
      // 上述代码,updateLane不是渲染车道的子集,则隐藏更新

      // 处理应跳过的更新
      if (shouldSkipUpdate) {
        
      } else {
        // 处理不应该跳过的更新
      }
      update = update.next;
      
    } while (update !== null && update !== first);
    

    if (newBaseQueueLast === null) {
      newBaseState = newState;
    } else {
      newBaseQueueLast.next = (newBaseQueueFirst: any);
    }

    // 表明新状态和旧状态不同,意味着状态发生了改变
    if (!is(newState, hook.memoizedState)) {
      // 标记工作中的 Fiber 节点接收到更新
      markWorkInProgressReceivedUpdate();

     // 检测到当前更新的车道与纠缠动作车道匹配
      if (didReadFromEntangledAsyncAction) {
        // 用于获取当前纠缠动作的 Promise 对象(entangledActionThenable)。
        const entangledActionThenable = peekEntangledActionThenable();

        // 若 entangledActionThenable 不为 null,说明存在纠缠的异步操作,此时会抛出这个 Promise 对象。在 React 中,抛出 Promise 是一种用于处理异步操作的机制,React 会捕获这个 Promise,暂停当前的渲染过程,等待 Promise 解决后再继续渲染。
        if (entangledActionThenable !== null) {
     
          throw entangledActionThenable;
        }
      }
    }

    hook.memoizedState = newState;
    hook.baseState = newBaseState;
    hook.baseQueue = newBaseQueueLast;

    queue.lastRenderedState = newState;
  }

  if (baseQueue === null) {
    queue.lanes = NoLanes;
  }

  const dispatch: Dispatch<A> = (queue.dispatch: any);
  return [hook.memoizedState, dispatch];
}

isHiddenUpdate是一个布尔值,通过比较updateLane和原始更新车道(update.lane)是否不同来确定当前更新是否为隐藏更新。如果updateLaneupdate.lane不同,说明原始的更新车道里包含OffscreenLane,此更新为隐藏更新。 

// 根据是否为隐藏更新来决定是否应跳过当前更新。
const shouldSkipUpdate = isHiddenUpdate
  // getWorkInProgressRootRenderLanes() 会返回当前正在处理的根节点的渲染车道
  ? !isSubsetOfLanes(getWorkInProgressRootRenderLanes(), updateLane)
  : !isSubsetOfLanes(renderLanes, updateLane);
// 上述代码,updateLane不是渲染车道的子集,则隐藏更新
if (shouldSkipUpdate) {
  // 创建新的update对象,并且
  const clone: Update<S, A> = {
    lane: updateLane,// 更新车道
    revertLane: update.revertLane,// 回滚车道
    action: update.action,// 
    hasEagerState: update.hasEagerState,// 是否有提前计算状态
    eagerState: update.eagerState,// 提前计算状态
    next: (null: any),
  };
  
  if (newBaseQueueLast === null) {
    // 将 newBaseQueueFirst 和 newBaseQueueLast 都设置为 clone,同时将 newBaseState 设置为当前的 newState。
    newBaseQueueFirst = newBaseQueueLast = clone;
    newBaseState = newState;
    
  } else {
    // 如果 newBaseQueueLast 不为 null,说明新基础队列已经存在其他更新,此时将克隆的更新 clone 添加到队列的末尾,即将 newBaseQueueLast 的 next 属性指向 clone,然后更新 newBaseQueueLast 为 clone。
    newBaseQueueLast = newBaseQueueLast.next = clone;
  }

  // 调用 mergeLanes 函数,将当前正在渲染的 Fiber 节点的 lanes 属性与当前更新的车道 updateLane 进行合并。这是为了记录当前 Fiber 节点所涉及的所有更新车道,以便后续的调度和处理。
  currentlyRenderingFiber.lanes = mergeLanes(
    currentlyRenderingFiber.lanes,
    updateLane,
  );

  // 标记跳过的更新车道
  markSkippedUpdateLanes(updateLane);
  
}
 if (shouldSkipUpdate) {} else {
  // 处理不应该跳过的更新

   //获取更新队列的回滚车道
  const revertLane = update.revertLane;
  // 通过检查 enableAsyncActions 和 revertLane 的值来判断当前更新是否为乐观更新。
  // enableAsyncActions 是一个布尔值,代表是否启用异步动作
  // revertLane代表回滚
  if (!enableAsyncActions || revertLane === NoLane) {
    // 非乐观更新的处理
    
    // 检查新基础队列是否不为空,即之前是否有跳过的更新。
    if (newBaseQueueLast !== null) {
      
      const clone: Update<S, A> = {
        lane: NoLane,
        revertLane: NoLane,
        action: update.action,
        hasEagerState: update.hasEagerState,
        eagerState: update.eagerState,
        next: (null: any),
      };
      newBaseQueueLast = newBaseQueueLast.next = clone;
    }

    // peekEntangledActionLane() 函数返回的纠缠动作车道
    if (updateLane === peekEntangledActionLane()) {
      // 读取了纠缠的异步动作
      didReadFromEntangledAsyncAction = true;
    }
  } else {
    
    // 乐观更新
    if (isSubsetOfLanes(renderLanes, revertLane)) {
   
      update = update.next;
      if (revertLane === peekEntangledActionLane()) {
        didReadFromEntangledAsyncAction = true;
      }
      continue;
      
    } else {

      const clone: Update<S, A> = {
        lane: NoLane,
        // Reuse the same revertLane so we know when the transition
        // has finished.
        revertLane: update.revertLane,
        action: update.action,
        hasEagerState: update.hasEagerState,
        eagerState: update.eagerState,
        next: (null: any),
      };
      
      if (newBaseQueueLast === null) {
        newBaseQueueFirst = newBaseQueueLast = clone;
        newBaseState = newState;
      } else {
        newBaseQueueLast = newBaseQueueLast.next = clone;
      }
      currentlyRenderingFiber.lanes = mergeLanes(
        currentlyRenderingFiber.lanes,
        revertLane,
      );
      markSkippedUpdateLanes(revertLane);
    }
  }

  // Process this update.
  const action = update.action;

  // 计算新状态
  if (update.hasEagerState) {
    newState = ((update.eagerState: any): S);
  } else {
    newState = reducer(newState, action);
  }
}


网站公告

今日签到

点亮在社区的每一天
去签到