前提
React函数组件里有很多hooks,他们在不同的阶段,dispatch的是不同的
在renderWithHooks函数里,会根据不同的阶段,分别赋值
这是在mount阶段和update的赋值
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
render阶段
if (didScheduleRenderPhaseUpdateDuringThisPass) {
ReactCurrentDispatcher.current = __DEV__
? HooksDispatcherOnRerenderInDEV
: HooksDispatcherOnRerender;
}
执行完函数后变成context
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
useState的实现入口,其中resolveDispatcher返回的就是ReactCurrentDispatcher.current
export function useState<S>(
initialState: (() => S) | S, //初始值 单值或者函数
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
当react初始节点时,current是为空的,useState调用的是HooksDispatcherOnMount
HooksDispatcherOnMount.useState实际就是mountState
mount阶段
mountState
mountState函数接收一个初始状态,可能是函数或值。函数内部调用了mountWorkInProgressHook获取当前正在处理的Hook节点。
然后判断initialState是否是函数类型,如果是就执行它获取初始值。接着将memoizedState和baseState都初始化为这个值。创建一个更新队列queue,设置基本的reducer为basicStateReducer,最后绑定dispatchSetState方法到dispatch函数上,并返回状态和dispatch
组件挂载 → mountState → 初始化状态 → 返回[state, dispatch]
↓
创建更新队列并与当前Fiber绑定
graph TD
A[开始] --> B{初始值是函数?}
B -->|是| C[执行函数获取状态]
B -->|否| D[直接使用初始值]
C & D --> E[设置memoized/baseState]
E --> F[创建更新队列]
F --> G[绑定dispatch函数]
G --> H[返回状态和dispatch]
function mountState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
// 1. 获取当前处理中的Hook节点
const hook = mountWorkInProgressHook();
// 2. 初始化状态处理(支持函数式初始值)
if (typeof initialState === 'function') {
initialState = initialState(); // 执行函数获取初始值
}
// 3. 设置Hook状态基准
hook.memoizedState = hook.baseState = initialState;
// 4. 创建更新队列
const queue: UpdateQueue<S, BasicStateAction<S>> = {
pending: null, // 待处理更新链表
lanes: NoLanes, // 更新优先级车道
dispatch: null, // 状态更新分发器
lastRenderedReducer: basicStateReducer, // 基础状态处理器
lastRenderedState: initialState, // 最后渲染状态
};
hook.queue = queue;
// 5. 绑定dispatch函数
const dispatch = (queue.dispatch = dispatchSetState.bind(
null,
currentlyRenderingFiber,
queue,
));
return [hook.memoizedState, dispatch];
}
mountWorkInProgressHook
mountWorkInProgressHook函数内部创建了一个新的Hook对象,包含memoizedState、baseState、baseQueue、queue和next等属性。接下来,函数检查当前是否有正在处理的Hook(workInProgressHook是否为null)。如果是第一次调用,就将当前渲染的Fiber节点的memoizedState指向这个新创建的Hook,并将workInProgressHook也指向它。否则,将新Hook添加到链表末尾,并更新workInProgressHook的指向
- 单向链表结构 :通过 next 指针形成执行顺序链,严格保持Hooks调用顺序
- 双指针管理 :
- currentlyRenderingFiber.memoizedState 指向链表头部
- workInProgressHook 始终指向链表尾部
- 状态隔离 :每个Hook维护独立的状态和更新队列,避免相互干扰 该函数在Hooks系统中的定位:
组件挂载 → mountWorkInProgressHook → 创建Hook链表 → 维护调用顺序
↓
实现Hooks规则的核心基础(保证每次渲染的Hook顺序一致性)
graph TD
A[创建Hook对象] --> B{是否是第一个Hook?}
B -->|是| C[绑定到Fiber.memoizedState]
B -->|否| D[追加到链表末尾]
C & D --> E[返回当前Hook指针]
function mountWorkInProgressHook(): Hook {
// 创建新的Hook对象
const hook: Hook = {
memoizedState: null, // 当前状态
baseState: null, // 基准状态
baseQueue: null, // 未处理的更新队列
queue: null, // 更新队列指针
next: null, // 链表指针
};
// 链表连接逻辑
if (workInProgressHook === null) {
// 第一个Hook:连接Fiber节点
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// 后续Hook:追加到链表末尾
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
dispatchSetState
函数接收三个参数:fiber、queue和action。
fiber代表当前的Fiber节点,queue是更新队列,action是新的状态值或更新函数。
然后,函数通过requestUpdateLane获取当前更新的优先级车道(lane)。创建一个新的更新对象update,包含优先级、action、预计算状态标记和下一个更新的指针
判断当前是否处于渲染阶段更新。如果是,将更新加入渲染阶段的队列。否则,进入常规更新处理流程
setState调用 → dispatchSetState → 创建更新对象 → 加入更新队列
↓
React并发模式状态更新的核心调度入口
graph TD
A[开始] --> B{是否渲染阶段更新?}
B -->|是| C[加入渲染阶段队列]
B -->|否| D{是否空队列?}
D -->|是| E[预计算状态]
E --> F{状态是否变化?}
F -->|否| G[跳过渲染]
F -->|是| H[加入常规队列]
D -->|否| H
C & G & H --> I[结束]
function dispatchSetState<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
) {
// 开发环境回调参数检查
if (__DEV__) {
if (typeof arguments[3] === 'function') {
console.error("状态更新不支持回调参数...");
}
}
// 1. 获取更新优先级车道
const lane = requestUpdateLane(fiber);
// 2. 创建更新对象
const update: Update<S, A> = {
lane,
action,
hasEagerState: false, // 预计算标记
eagerState: null, // 预计算结果
next: null, // 链表指针
};
// 3. 判断渲染阶段更新
if (isRenderPhaseUpdate(fiber)) {
enqueueRenderPhaseUpdate(queue, update);
} else {
// 4. 非渲染阶段更新处理
const alternate = fiber.alternate;
if (fiber.lanes === NoLanes && alternate?.lanes === NoLanes) {
// 5. 快速路径:预计算状态
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
try {
const currentState = queue.lastRenderedState;
const eagerState = lastRenderedReducer(currentState, action);
// 6. 状态比较优化
update.hasEagerState = true;
update.eagerState = eagerState;
if (is(eagerState, currentState)) {
// 状态相同则跳过渲染
enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update);
return;
}
} catch (error) {
// 静默处理错误,留到渲染阶段抛出
}
}
}
// 7. 常规更新路径
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane, requestEventTime());
entangleTransitionUpdate(root, queue, lane);
}
}
// 8. 开发工具标记
markUpdateInDevTools(fiber, lane, action);
}
后续通过scheduleUpdateOnFiber对fiber进行调度更新