第一天:解析生成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);
}