Hooks在react中的底层实现原理

272 阅读5分钟

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 系统通过精密的链表管理、状态缓存、优先级调度等机制,实现了在函数组件中管理状态和副作用的能力,同时保持了良好的性能和开发体验。