当前位置: 首页 > news >正文

React19源码系列之Hooks(useState)

useState的使用

1、简单基础用法:

import React, { useState } from 'react';function Counter() {// 声明一个名为 count 的状态变量,初始值为 0const [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, // 当前渲染到fiberqueue,// 更新队列): 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);// 返回关联的 FiberRootreturn 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 的 lanessourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);// 2. 标记双缓存 Fiber 的 laneslet 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. 向上遍历父节点,标记 childLaneslet 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>] {// 获取正在工作的 Hookconst 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);}
}

相关文章:

  • C++ 类的知识点
  • 【Docker 05】Container - 容器
  • Spring AI的ChatClient和ChatModel接口
  • Node.js 中的 Token 认证机制详解
  • 动态规划之斐波那契数(一)
  • java 集合 泛型
  • (LeetCode 每日一题) 1432. 改变一个整数能得到的最大差值(贪心)
  • 编译链接实战(30)strip移除了哪些内容
  • JVM 类加载过程/对象创建过程/双亲委派机制/垃圾回收机制
  • 大模型微调(Fine-tuning)概览
  • Vue-Leaflet地图组件开发(四)高级功能与深度优化探索
  • 基于51单片机的温度和液位监测系统(串口传输)
  • Vue 性能优化
  • kicad运行时出错,_Pnext->_Myproxy = nullptr;访问内存出错
  • 自我实现的量子隐喻:在可能性场域中动态拓展涌现节点
  • 安装前端vite框架,后端安装fastapi框架
  • Multisim仿真Buck电路基本拓扑
  • 进程和线程区别、管道和套接字、共享变量、TCP三次握手,是否可以少一次握手、子进程和主进程区别和API——Nodejs
  • Spring Cloud Gateway 全面学习指南
  • LabVIEW电路板焊点自动检测
  • 山东网站建设公司电话/怎么在百度上做网站
  • 学做古装网站/宁波seo整站优化软件
  • 网站建设兼职招聘/久久seo综合查询
  • 青岛黄岛区做网站设计的/软文营销范文100字
  • 杭州电子网站建设方案/百度通用网址
  • 动画制作软件哪个好用/提升seo搜索排名