基于 React 19 源码深度解析
2026-03-13 | 技术深度解读
Hooks 是 React 16.8 引入的新特性,让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
| 版本 | 特性 | 数据结构 |
|---|---|---|
| React 15 | Class Component | 实例属性 |
| React 16.0 | Fiber 架构 | Fiber 树 |
| React 16.8 | Hooks API | Hook 链表 |
| React 18 | 并发模式 | 优先级队列 |
| React 19 | use(), Actions | Thenable 支持 |
关键洞察:Hooks 的核心是使用链表在 Fiber 节点上存储状态,实现函数组件的状态持久化。
设计精髓:使用链表而非数组,是因为 Hooks 在渲染时按顺序调用,链表可以高效地动态扩展。
export type Hook = {
memoizedState: any, // Hook 的记忆状态
baseState: any, // 基础状态(用于更新计算)
baseQueue: Update | null,// 待处理的更新队列
queue: any, // 更新队列对象
next: Hook | null, // 指向下一个 Hook
};
const hook: Hook = {
memoizedState: null, // 不同 Hook 存储不同内容
baseState: null, // 基础状态
baseQueue: null, // 基础更新队列
queue: null, // 更新调度器
next: null, // 下一个 Hook
};
| Hook 类型 | memoizedState 存储 |
|---|---|
| useState | state 值 |
| useEffect | Effect 对象 |
| useRef | {current: value} |
| useMemo | [value, deps] |
| useCallback | [callback, deps] |
function FiberNode(tag, pendingProps, key, mode) {
// ... 其他属性
// Hooks 链表的头节点
this.memoizedState = null;
// 更新队列(存储 Effects)
this.updateQueue = null;
}
function mountWorkInProgressHook(): Hook {
const hook: Hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
// 第一个 Hook
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// 追加到链表末尾
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
核心逻辑:创建 Hook 节点,追加到链表末尾,返回当前 Hook。
function updateWorkInProgressHook(): Hook {
// 从 current fiber 获取下一个 Hook
let nextCurrentHook;
if (currentHook === null) {
const current = currentlyRenderingFiber.alternate;
nextCurrentHook = current !== null ? current.memoizedState : null;
} else {
nextCurrentHook = currentHook.next;
}
// 复用或创建新的 Hook
const newHook: Hook = {
memoizedState: currentHook.memoizedState,
baseState: currentHook.baseState,
baseQueue: currentHook.baseQueue,
queue: currentHook.queue,
next: null,
};
// 追加到 workInProgress 链表
workInProgressHook = workInProgressHook.next = newHook;
return workInProgressHook;
}
export function useState<S>(
initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
// 内部实现
function mountState<S>(initialState) {
const hook = mountWorkInProgressHook();
hook.memoizedState = hook.baseState = initialState;
const queue = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState,
};
hook.queue = queue;
const dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue);
queue.dispatch = dispatch;
return [hook.memoizedState, dispatch];
}
function mountEffect(
create: () => (() => void) | void,
deps: Array<mixed> | void | null,
): void {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= PassiveEffect;
hook.memoizedState = pushEffect(
HookHasEffect | HookPassive,
createEffectInstance(),
create,
nextDeps,
);
}
关键:useEffect 的 memoizedState 存储的是 Effect 对象,而不是简单的状态值。
export type Update<S, A> = {
lane: Lane, // 优先级
revertLane: Lane, // 回退优先级(乐观更新)
action: A, // 更新动作
hasEagerState: boolean, // 是否已急切计算
eagerState: S | null, // 急切计算的状态
next: Update<S, A>, // 下一个更新(环形链表)
gesture: null | ScheduledGesture,
};
export type UpdateQueue<S, A> = {
pending: Update<S, A> | null, // 待处理的更新(环形)
lanes: Lanes,
dispatch: ((A) => mixed) | null,
lastRenderedReducer: ((S, A) => S) | null,
lastRenderedState: S | null,
};
export type Effect = {
tag: HookFlags, // Effect 类型标记
inst: EffectInstance, // 实例对象(存储 destroy)
create: () => (() => void) | void, // 创建函数
deps: Array<mixed> | void | null, // 依赖数组
next: Effect, // 指向下一个 Effect(循环)
};
function pushEffect(tag, inst, create, deps): Effect {
const effect: Effect = { tag, inst, create, deps, next: null };
const componentUpdateQueue = currentlyRenderingFiber.updateQueue;
const lastEffect = componentUpdateQueue.lastEffect;
if (lastEffect === null) {
// 第一个 Effect,自己指向自己
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
// 插入到循环链表中
const firstEffect = lastEffect.next;
lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
return effect;
}
React 使用 Dispatcher 对象来区分不同阶段的 Hooks 行为:
const HooksDispatcherOnMount: Dispatcher = {
useState: mountState,
useEffect: mountEffect,
// ... mount 版本
};
const HooksDispatcherOnUpdate: Dispatcher = {
useState: updateState,
useEffect: updateEffect,
// ... update 版本
};
const ContextOnlyDispatcher: Dispatcher = {
useState: throwInvalidHookError,
useEffect: throwInvalidHookError,
// ... 在非组件上下文中抛错
};
作用:确保 Hooks 只能在函数组件内部调用,并在不同阶段执行不同逻辑。
export function renderWithHooks(
current: Fiber | null,
workInProgress: Fiber,
Component: (p: Props) => any,
props: Props,
nextRenderLanes: Lanes,
): any {
renderLanes = nextRenderLanes;
currentlyRenderingFiber = workInProgress;
// 重置 Hooks 链表
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
// 设置对应的 Dispatcher
ReactSharedInternals.H =
current === null || current.memoizedState === null
? HooksDispatcherOnMount
: HooksDispatcherOnUpdate;
// 执行组件函数
let children = Component(props);
// 重置
ReactSharedInternals.H = ContextOnlyDispatcher;
return children;
}
重要:Hooks 的顺序必须保持一致,否则会导致状态错乱!
function Component() {
const [count, setCount] = useState(0); // Hook 1
const [name, setName] = useState(''); // Hook 2
useEffect(() => {}); // Hook 3
}
// 第一次渲染:
// Fiber.memoizedState → Hook1(count) → Hook2(name) → Hook3(effect)
// 第二次渲染:
// 必须按相同顺序调用,才能正确复用状态!
// ❌ 错误示例:条件调用
function BadComponent({ isLoggedIn }) {
if (isLoggedIn) {
const [user, setUser] = useState(null); // 顺序变化!
}
}
规则:只能在函数最顶层调用 Hooks,不要在循环、条件或嵌套函数中调用。
// ReactHooks.js - 入口
export function useState<S>(initialState) {
const dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
// ReactFiberHooks.js - 实现
function mountState<S>(initialState) {
const hook = mountWorkInProgressHook();
// 初始化状态
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
// 创建更新队列
const queue: UpdateQueue = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState,
};
hook.queue = queue;
// 绑定 dispatch
const dispatch = dispatchSetState.bind(
null,
currentlyRenderingFiber,
queue
);
queue.dispatch = dispatch;
return [hook.memoizedState, dispatch];
}
const hook = mountWorkInProgressHook();
hook.memoizedState = hook.baseState = initialState;
const queue = { pending: null, dispatch: null, ... };
const dispatch = dispatchSetState.bind(null, fiber, queue);
function updateState<S>(initialState) {
// updateState 本质是 updateReducer 的特殊形式
return updateReducer(basicStateReducer, initialState);
}
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
return typeof action === 'function' ? action(state) : action;
}
function updateReducer<S, A>(reducer, initialArg, init?) {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
// 处理更新队列...
let newState = hook.baseState;
let update = queue.pending;
do {
newState = reducer(newState, update.action);
update = update.next;
} while (update !== queue.pending);
hook.memoizedState = newState;
return [hook.memoizedState, queue.dispatch];
}
function dispatchSetState<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
action: A,
): void {
const lane = requestUpdateLane(fiber);
const update: Update<S, A> = {
lane,
revertLane: NoLane,
action,
hasEagerState: false,
eagerState: null,
next: null,
};
if (isRenderPhaseUpdate(fiber)) {
// 渲染阶段更新:加入 pending 队列
enqueueRenderPhaseUpdate(queue, update);
} else {
// 调度更新
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
if (root !== null) {
scheduleUpdateOnFiber(root, fiber, lane);
}
}
}
// ReactHooks.js - 入口
export function useEffect(create, deps) {
const dispatcher = resolveDispatcher();
return dispatcher.useEffect(create, deps);
}
// ReactFiberHooks.js - mount 版本
function mountEffect(create, deps) {
return mountEffectImpl(
PassiveEffect | PassiveStaticEffect,
HookPassive,
create,
deps,
);
}
function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
createEffectInstance(),
create,
nextDeps,
);
}
const hook = mountWorkInProgressHook();
fiber.flags |= PassiveEffect;
const effect = {
tag: HookHasEffect | HookPassive,
create: create,
deps: deps,
// ...
};
pushEffect(effect);
注意:Effect 存储在 Fiber.updateQueue 的循环链表中,而不是 Hook.memoizedState。
function updateEffect(create, deps) {
return updateEffectImpl(PassiveEffect, HookPassive, create, deps);
}
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const effect: Effect = hook.memoizedState;
const inst = effect.inst;
// 比较依赖
if (currentHook !== null) {
if (nextDeps !== null) {
const prevEffect = currentHook.memoizedState;
const prevDeps = prevEffect.deps;
if (areHookInputsEqual(nextDeps, prevDeps)) {
// 依赖未变,只推入 effect 但不标记 HasEffect
hook.memoizedState = pushEffect(hookFlags, inst, create, nextDeps);
return;
}
}
}
// 依赖改变,标记 HasEffect
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
inst,
create,
nextDeps,
);
}
function pushEffect(tag, inst, create, deps): Effect {
const effect: Effect = {
tag,
inst,
create,
deps,
next: null,
};
let componentUpdateQueue = currentlyRenderingFiber.updateQueue;
if (componentUpdateQueue === null) {
componentUpdateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = componentUpdateQueue;
}
const lastEffect = componentUpdateQueue.lastEffect;
if (lastEffect === null) {
// 第一个 effect,自引用形成循环
componentUpdateQueue.lastEffect = effect.next = effect;
} else {
// 插入到最后一个和第一个之间
const firstEffect = lastEffect.next;
lastEffect.next = effect;
effect.next = firstEffect;
componentUpdateQueue.lastEffect = effect;
}
return effect;
}
function mountReducer<S, I, A>(reducer, initialArg, init?) {
const hook = mountWorkInProgressHook();
let initialState;
if (init !== undefined) {
initialState = init(initialArg);
} else {
initialState = initialArg;
}
hook.memoizedState = hook.baseState = initialState;
const queue: UpdateQueue<S, A> = {
pending: null,
lanes: NoLanes,
dispatch: null,
lastRenderedReducer: reducer,
lastRenderedState: initialState,
};
hook.queue = queue;
const dispatch = dispatchReducerAction.bind(
null,
currentlyRenderingFiber,
queue,
);
queue.dispatch = dispatch;
return [hook.memoizedState, dispatch];
}
与 useState 的区别:useState 使用 basicStateReducer,useReducer 使用用户提供的 reducer。
function mountMemo<T>(nextCreate: () => T, deps) {
const hook = mountWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
function updateMemo<T>(nextCreate: () => T, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
const prevState = hook.memoizedState;
if (nextDeps !== null) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0]; // 依赖未变,返回缓存值
}
}
const nextValue = nextCreate();
hook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
// useCallback 本质是 useMemo 的特例
function mountCallback(callback, deps) {
const hook = mountWorkInProgressHook();
hook.memoizedState = [callback, deps];
return callback;
}
function mountRef<T>(initialValue: T): {current: T} {
const hook = mountWorkInProgressHook();
const ref = {current: initialValue};
hook.memoizedState = ref;
return ref;
}
function updateRef<T>(initialValue: T): {current: T} {
const hook = updateWorkInProgressHook();
return hook.memoizedState; // 直接返回已有的 ref 对象
}
export function useContext<T>(Context: ReactContext<T>): T {
const dispatcher = resolveDispatcher();
return dispatcher.useContext(Context);
}
// 在 Dispatcher 中
useContext: readContext,
// ReactFiberNewContext.js
export function readContext<T>(context: ReactContext<T>): T {
// 读取当前 Fiber 的 context 值
// 不需要 Hook 节点!
return context._currentValue;
}
注意:useContext 不创建 Hook 节点,直接从 Context 对象读取值。但会订阅 Context 变化。
function mountTransition() {
const stateHook = mountStateImpl(false);
// startTransition 函数是稳定的
const start = startTransition.bind(
null,
currentlyRenderingFiber,
stateHook.queue,
true, // pendingState
false, // finishedState
);
const hook = mountWorkInProgressHook();
hook.memoizedState = start;
return [false, start];
}
function updateTransition() {
const [booleanOrThenable] = updateState(false);
const hook = updateWorkInProgressHook();
const start = hook.memoizedState;
const isPending = typeof booleanOrThenable === 'boolean'
? booleanOrThenable
: useThenable(booleanOrThenable);
return [isPending, start];
}
function updateDeferredValue<T>(value: T, initialValue?: T): T {
const hook = updateWorkInProgressHook();
const prevValue: T = currentHook.memoizedState;
if (is(value, prevValue)) {
// 值未变,直接返回
return value;
}
const shouldDeferValue =
!includesOnlyNonUrgentLanes(renderLanes) &&
!isRenderingDeferredWork();
if (shouldDeferValue) {
// 紧急更新:延迟渲染新值
const deferredLane = requestDeferredLane();
currentlyRenderingFiber.lanes = mergeLanes(
currentlyRenderingFiber.lanes,
deferredLane,
);
markSkippedUpdateLanes(deferredLane);
return prevValue; // 返回旧值
} else {
// 非紧急:直接使用新值
markWorkInProgressReceivedUpdate();
hook.memoizedState = value;
return value;
}
}
function mountId(): string {
const hook = mountWorkInProgressHook();
const root = getWorkInProgressRoot();
const identifierPrefix = root.identifierPrefix;
let id;
if (getIsHydrating()) {
// SSR hydration:使用服务端生成的 ID
const treeId = getTreeId();
id = '_' + identifierPrefix + 'R_' + treeId;
const localId = localIdCounter++;
if (localId > 0) {
id += 'H' + localId.toString(32);
}
id += '_';
} else {
// 客户端:生成唯一 ID
const globalClientId = globalClientIdCounter++;
id = '_' + identifierPrefix + 'r_' +
globalClientId.toString(32) + '_';
}
hook.memoizedState = id;
return id;
}
不要在循环、条件或嵌套函数中调用 Hooks
原因:Hooks 依赖调用顺序来匹配状态
只在函数组件或自定义 Hook 中调用
原因:需要 Dispatcher 上下文
// ❌ 违反规则
if (condition) {
const [value, setValue] = useState(0); // 顺序不稳定
}
// ✅ 正确
const [value, setValue] = useState(0);
if (condition) {
// 使用 value
}
// React 在 DEV 模式下检测 Hooks 调用顺序
let hookTypesDev: Array<HookType> | null = null;
let hookTypesUpdateIndexDev: number = -1;
function updateHookTypesDev() {
const hookName = currentHookNameInDev;
if (hookTypesDev !== null) {
hookTypesUpdateIndexDev++;
if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) {
warnOnHookMismatchInDev(hookName); // 警告顺序不匹配
}
}
}
function warnOnHookMismatchInDev(currentHookName) {
console.error(
'React has detected a change in the order of Hooks called by %s.',
componentName
);
}
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
console.log(count); // ❌ 永远是 0(闭包捕获)
}, 1000);
return () => clearInterval(id);
}, []); // 空依赖数组
}
// 解决方案 1:添加依赖
useEffect(() => {
const id = setInterval(() => {
console.log(count); // ✅ 每次都是最新值
}, 1000);
return () => clearInterval(id);
}, [count]); // 添加依赖
// 解决方案 2:使用 useRef
const countRef = useRef(count);
countRef.current = count;
useEffect(() => {
const id = setInterval(() => {
console.log(countRef.current); // ✅ 始终最新
}, 1000);
return () => clearInterval(id);
}, []);
// ❌ Stale Closure
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log(count); // 捕获初始 count
}, []); // 缺少 count 依赖
// ✅ 正确做法
const handleClick = useCallback(() => {
console.log(count);
}, [count]); // 添加 count 依赖
// ✅ 或使用函数式更新
const handleClick = useCallback(() => {
setCount(c => {
console.log(c); // 使用最新的 c
return c + 1;
});
}, []); // 不需要 count 依赖
| 策略 | 实现 | 效果 |
|---|---|---|
| useMemo | 缓存计算结果 | 避免重复计算 |
| useCallback | 缓存函数引用 | 避免子组件重渲染 |
| React.memo | 浅比较 props | 跳过不必要的渲染 |
| useDeferredValue | 延迟更新 | 保持 UI 响应 |
| useTransition | 非阻塞更新 | 优先级调度 |
原则:不要过早优化,先测量性能瓶颈,再针对性优化。
// ❌ 过度依赖
useEffect(() => {
doSomething(config.url, config.method);
}, [config.url, config.method]); // 分别列出
// ✅ 使用 useMemo 减少依赖
const configDeps = useMemo(() => ({
url: config.url,
method: config.method,
}), [config.url, config.method]);
useEffect(() => {
doSomething(configDeps);
}, [configDeps]); // 单一依赖
// ❌ 每次渲染都重新创建
const fetchData = useCallback(() => {
fetch(url + query);
}, [url, query]); // query 可能频繁变化
// ✅ 使用 ref 存储可变值
const queryRef = useRef(query);
queryRef.current = query;
const fetchData = useCallback(() => {
fetch(url + queryRef.current);
}, [url]); // 减少依赖
function dispatchSetStateInternal(fiber, queue, action, lane) {
// 如果当前没有其他更新,可以急切计算新状态
if (
fiber.lanes === NoLanes &&
(alternate === null || alternate.lanes === NoLanes)
) {
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
const currentState = queue.lastRenderedState;
const eagerState = lastRenderedReducer(currentState, action);
update.hasEagerState = true;
update.eagerState = eagerState;
// 如果状态未变,可以完全跳过渲染
if (is(eagerState, currentState)) {
enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update);
return false; // 不需要调度更新
}
}
}
// 需要调度更新
const root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);
scheduleUpdateOnFiber(root, fiber, lane);
return true;
}
// bailoutHooks 实现
export function bailoutHooks(
current: Fiber,
workInProgress: Fiber,
lanes: Lanes,
): void {
workInProgress.updateQueue = current.updateQueue;
workInProgress.flags &= ~(PassiveEffect | UpdateEffect);
current.lanes = removeLanes(current.lanes, lanes);
}
// 使用场景
if (current !== null && current.memoizedState !== null) {
// 有现有状态,检查是否可以 bailout
if (checkDidRenderIdHook()) {
// 状态未变,跳过渲染
return bailoutHooks(current, workInProgress, renderLanes);
}
}
// 在 Strict Mode 下,组件会渲染两次
const shouldDoubleRenderDEV =
__DEV__ && (workInProgress.mode & StrictLegacyMode) !== NoMode;
shouldDoubleInvokeUserFnsInHooksDEV = shouldDoubleRenderDEV;
let children = Component(props);
if (shouldDoubleRenderDEV) {
// 第二次渲染
setIsStrictModeForDevtools(true);
try {
children = renderWithHooksAgain(
workInProgress,
Component,
props,
secondArg,
);
} finally {
setIsStrictModeForDevtools(false);
}
}
目的:帮助发现副作用和不纯的渲染逻辑,确保组件可以安全地多次渲染。
// React DevTools 可以读取 Hooks 链表
if (__DEV__) {
workInProgress._debugHookTypes = hookTypesDev;
// 存储 thenable state 用于调试
if (workInProgress.dependencies === null) {
if (thenableState !== null) {
workInProgress.dependencies = {
lanes: NoLanes,
firstContext: null,
_debugThenableState: thenableState,
};
}
}
}
// DevTools 可以访问:
// - fiber._debugHookTypes: Hook 类型数组
// - fiber.memoizedState: Hook 链表
// - 每个 Hook 的 memoizedState
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// 在 DevTools 中显示
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
// 在控制台访问当前组件的 Fiber
const fiber = document.querySelector('#root')._reactRootContainer._internalRoot.current;
let hook = fiber.memoizedState;
while (hook) {
console.log('Hook:', hook);
hook = hook.next;
}
// ❌ 在循环中调用 Hooks
items.forEach(item => {
const [value, setValue] = useState(item.value);
});
// ❌ 在条件语句中调用 Hooks
if (condition) {
const [value, setValue] = useState(0);
}
// ❌ 在普通函数中调用 Hooks
function handleClick() {
const [value, setValue] = useState(0); // 错误!
}
// ❌ 过度使用 useMemo
const value = useMemo(() => a + b, [a, b]); // 简单计算不需要
// ❌ 忘记清理副作用
useEffect(() => {
const id = setInterval(() => {}, 1000);
// 缺少 return () => clearInterval(id);
}, []);
理解 Hooks 链表结构,是掌握 React 内部机制的关键!
2026-03-13 | 查克小助理 🦞