React Hooks 底层实现原理详解
1. Hooks 的整体架构
React Fiber 与 Hooks 的关系
// Fiber 节点结构(简化)
const FiberNode = {
type: Component, // 组件类型
memoizedState: null, // Hook 链表的头节点
memoizedProps: {}, // 缓存的 props
updateQueue: null, // 更新队列
alternate: null, // 双缓冲中的另一个 Fiber 节点
// ... 其他属性
};
Hook 对象的数据结构
// 每个 Hook 的基本结构
const Hook = {
memoizedState: any, // 存储 Hook 的状态值
baseState: any, // 基础状态
baseQueue: Update | null, // 基础更新队列
queue: UpdateQueue | null, // 当前更新队列
next: Hook | null, // 指向下一个 Hook
};
2. Hook 链表的管理机制
全局变量管理
// React 内部的全局变量
let currentlyRenderingFiber = null; // 当前正在渲染的 Fiber 节点
let currentHook = null; // 当前 Hook 指针(用于更新)
let workInProgressHook = null; // 工作中的 Hook 指针(用于构建新链表)
let didScheduleRenderPhaseUpdate = false; // 是否在渲染阶段调度了更新
Hook 链表的构建过程
// 首次渲染时创建 Hook
function mountWorkInProgressHook() {
const hook = {
memoizedState: null,
baseState: null,
baseQueue: null,
queue: null,
next: null,
};
if (workInProgressHook === null) {
// 第一个 Hook,设置为链表头
currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
} else {
// 后续 Hook,添加到链表尾部
workInProgressHook = workInProgressHook.next = hook;
}
return workInProgressHook;
}
// 更新时获取对应的 Hook
function updateWorkInProgressHook() {
let nextCurrentHook;
if (currentHook === null) {
// 第一个 Hook
const current = currentlyRenderingFiber.alternate;
if (current !== null) {
nextCurrentHook = current.memoizedState;
} else {
nextCurrentHook = null;
}
} else {
// 后续 Hook,沿着链表向前移动
nextCurrentHook = currentHook.next;
}
currentHook = nextCurrentHook;
// 创建新的 Hook 对象
const newHook = {
memoizedState: currentHook.memoizedState,
baseState: currentHook.baseState,
baseQueue: currentHook.baseQueue,
queue: currentHook.queue,
next: null,
};
if (workInProgressHook === null) {
currentlyRenderingFiber.memoizedState = workInProgressHook = newHook;
} else {
workInProgressHook = workInProgressHook.next = newHook;
}
return workInProgressHook;
}
3. useState 的完整实现
更新队列的数据结构
// 更新对象
const Update = {
action: any, // 更新动作(值或函数)
eagerReducer: Reducer | null, // 预计算的 reducer
eagerState: any, // 预计算的状态
next: Update | null, // 下一个更新
priority: number, // 优先级
};
// 更新队列
const UpdateQueue = {
pending: Update | null, // 待处理的更新链表
dispatch: Function, // dispatch 函数
lastRenderedReducer: Function,// 上次渲染使用的 reducer
lastRenderedState: any, // 上次渲染的状态
};
useState 的 Mount 阶段
function mountState(initialState) {
const hook = mountWorkInProgressHook();
// 处理初始状态
if (typeof initialState === 'function') {
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
// 创建更新队列
const queue = (hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState,
});
// 创建 dispatch 函数
const dispatch = (queue.dispatch = dispatchAction.bind(
null,
currentlyRenderingFiber,
queue
));
return [hook.memoizedState, dispatch];
}
// 基础状态 reducer
function basicStateReducer(state, action) {
return typeof action === 'function' ? action(state) : action;
}
useState 的 Update 阶段
function updateState(initialState) {
return updateReducer(basicStateReducer, initialState);
}
function updateReducer(reducer, initialArg, init) {
const hook = updateWorkInProgressHook();
const queue = hook.queue;
queue.lastRenderedReducer = reducer;
const current = currentHook;
let baseQueue = current.baseQueue;
// 处理待处理的更新
const pendingQueue = queue.pending;
if (pendingQueue !== null) {
// 合并更新队列
if (baseQueue !== null) {
const baseFirst = baseQueue.next;
const pendingFirst = pendingQueue.next;
baseQueue.next = pendingFirst;
pendingQueue.next = baseFirst;
}
current.baseQueue = baseQueue = pendingQueue;
queue.pending = null;
}
if (baseQueue !== null) {
// 处理更新队列,计算新状态
const first = baseQueue.next;
let newState = current.baseState;
let newBaseState = null;
let newBaseQueueFirst = null;
let newBaseQueueLast = null;
let update = first;
do {
const updatePriority = update.priority;
if (updatePriority < renderPriority) {
// 优先级不够,跳过这个更新
const clone = {
priority: updatePriority,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: null,
};
if (newBaseQueueLast === null) {
newBaseQueueFirst = newBaseQueueLast = clone;
newBaseState = newState;
} else {
newBaseQueueLast = newBaseQueueLast.next = clone;
}
} else {
// 处理这个更新
if (newBaseQueueLast !== null) {
const clone = {
priority: NoWork,
action: update.action,
eagerReducer: update.eagerReducer,
eagerState: update.eagerState,
next: null,
};
newBaseQueueLast = newBaseQueueLast.next = clone;
}
// 计算新状态
if (update.eagerReducer === reducer) {
newState = update.eagerState;
} else {
const action = update.action;
newState = reducer(newState, action);
}
}
update = update.next;
} while (update !== null && update !== first);
if (newBaseQueueLast === null) {
newBaseState = newState;
} else {
newBaseQueueLast.next = newBaseQueueFirst;
}
hook.memoizedState = newState;
hook.baseState = newBaseState;
hook.baseQueue = newBaseQueueFirst;
queue.lastRenderedState = newState;
}
const dispatch = queue.dispatch;
return [hook.memoizedState, dispatch];
}
dispatch 函数的实现
function dispatchAction(fiber, queue, action) {
const update = {
action,
eagerReducer: null,
eagerState: null,
next: null,
priority: getCurrentPriorityLevel(),
};
// 添加到更新队列
const pending = queue.pending;
if (pending === null) {
update.next = update; // 创建循环链表
} else {
update.next = pending.next;
pending.next = update;
}
queue.pending = update;
const alternate = fiber.alternate;
if (
fiber === currentlyRenderingFiber ||
(alternate !== null && alternate === currentlyRenderingFiber)
) {
// 在渲染阶段的更新
didScheduleRenderPhaseUpdate = true;
} else {
// 优化:尝试预计算状态
if (
fiber.expirationTime === NoWork &&
(alternate === null || alternate.expirationTime === NoWork)
) {
const lastRenderedReducer = queue.lastRenderedReducer;
if (lastRenderedReducer !== null) {
try {
const currentState = queue.lastRenderedState;
const eagerState = lastRenderedReducer(currentState, action);
update.eagerReducer = lastRenderedReducer;
update.eagerState = eagerState;
if (Object.is(eagerState, currentState)) {
// 状态没有变化,跳过更新
return;
}
} catch (error) {
// 预计算失败,继续正常流程
}
}
}
// 调度更新
scheduleWork(fiber, expirationTime);
}
}
4. useEffect 的实现
Effect 的数据结构
const Effect = {
tag: number, // effect 类型标记
create: () => (() => void) | void, // effect 函数
destroy: (() => void) | void, // 清理函数
deps: Array<any> | null, // 依赖数组
next: Effect, // 下一个 effect(循环链表)
};
useEffect 的实现
function mountEffect(create, deps) {
return mountEffectImpl(
UpdateEffect | PassiveEffect,
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,
create,
undefined,
nextDeps
);
}
function updateEffect(create, deps) {
return updateEffectImpl(UpdateEffect, HookPassive, create, deps);
}
function updateEffectImpl(fiberFlags, hookFlags, create, deps) {
const hook = updateWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
let destroy = undefined;
if (currentHook !== null) {
const prevEffect = currentHook.memoizedState;
destroy = prevEffect.destroy;
if (nextDeps !== null) {
const prevDeps = prevEffect.deps;
// 比较依赖数组
if (areHookInputsEqual(nextDeps, prevDeps)) {
// 依赖没有变化,不执行 effect
pushEffect(hookFlags, create, destroy, nextDeps);
return;
}
}
}
currentlyRenderingFiber.flags |= fiberFlags;
hook.memoizedState = pushEffect(
HookHasEffect | hookFlags,
create,
destroy,
nextDeps
);
}
// 依赖数组比较
function areHookInputsEqual(nextDeps, prevDeps) {
if (prevDeps === null) {
return false;
}
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (Object.is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}
5. 渲染阶段的 Hook 处理
渲染开始时的初始化
function renderWithHooks(
current,
workInProgress,
Component,
props,
secondArg,
nextRenderExpirationTime
) {
renderExpirationTime = nextRenderExpirationTime;
currentlyRenderingFiber = workInProgress;
// 重置 Hook 状态
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
// 设置 Hook 调度器
ReactCurrentDispatcher.current =
current === null || current.memoizedState === null
? HooksDispatcherOnMount // 首次渲染
: HooksDispatcherOnUpdate; // 更新渲染
// 执行函数组件
let children = Component(props, secondArg);
// 处理渲染阶段的更新
if (didScheduleRenderPhaseUpdate) {
do {
didScheduleRenderPhaseUpdate = false;
numberOfReRenders += 1;
// 重置 Hook 指针
currentHook = null;
workInProgressHook = null;
workInProgress.updateQueue = null;
ReactCurrentDispatcher.current = HooksDispatcherOnRerender;
children = Component(props, secondArg);
} while (didScheduleRenderPhaseUpdate);
}
// 清理
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
renderExpirationTime = NoWork;
currentlyRenderingFiber = null;
currentHook = null;
workInProgressHook = null;
return children;
}
Hook 调度器的定义
const HooksDispatcherOnMount = {
useState: mountState,
useEffect: mountEffect,
useRef: mountRef,
useCallback: mountCallback,
useMemo: mountMemo,
// ... 其他 hooks
};
const HooksDispatcherOnUpdate = {
useState: updateState,
useEffect: updateEffect,
useRef: updateRef,
useCallback: updateCallback,
useMemo: updateMemo,
// ... 其他 hooks
};
6. 为什么 Hooks 有使用规则
规则的必要性
// ❌ 错误使用 - 条件调用会破坏链表结构
function BadComponent({ condition }) {
const [count, setCount] = useState(0);
if (condition) {
const [name, setName] = useState(''); // 可能不会执行
}
const inputRef = useRef(null);
// 第一次渲染链表:useState -> useState -> useRef
// 第二次渲染链表:useState -> useRef (少了一个节点)
// 导致 Hook 对应关系错乱
}
// ✅ 正确使用
function GoodComponent({ condition }) {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
const inputRef = useRef(null);
// 每次渲染的链表结构都一致
}
React 的检测机制
function throwInvalidHookError() {
throw new Error(
'Invalid hook call. Hooks can only be called inside of the body of a function component.'
);
}
// 在非法上下文中调用 Hook 时的调度器
const ContextOnlyDispatcher = {
useState: throwInvalidHookError,
useEffect: throwInvalidHookError,
// ... 其他 hooks 都指向错误函数
};
这套 Hooks 系统通过精密的链表管理、状态缓存、优先级调度等机制,实现了在函数组件中管理状态和副作用的能力,同时保持了良好的性能和开发体验。