Skip to content

useEffect挂载实现

packages/react/src/ReactHooks.js

js
export function useEffect(create) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useEffect(create);
}

packages/react/src/React.js

js
import { useReducer, useState, useEffect } from './ReactHooks';
import ReactSharedInternals from './ReactSharedInternals';
export {
  useReducer,
  useState,
  useEffect,
  ReactSharedInternals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
}

packages/react/index.js

js
export { 
    __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
    useState,
    useReducer,
    useEffect
 }

packages/react-reconciler/src/ReactFiberHooks.js

js
import { Passive as PassiveEffect } from './ReactFiberFlags';
import { HasEffect as HookHasEffect, Passive as HookPassive } from './ReactHookEffectTags';
const HooksDispatcherOnMount = {
  useReducer: mountReducer,  // 在mount期间,使用mountReducer处理useReducer
  useState: mountState,
  useEffect: mountEffect
}
const HooksDispatcherOnUpdate = {
  useReducer: updateReducer,
  useState: updateState,
  useEffect: updateEffect
}
function mountEffect(create, deps) {
  return mountEffectImpl(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 pushEffect(tag, create, destroy, deps) {
  const effect = {
    tag,
    create,
    destroy,
    deps,
    next: null
  }
  let componentUpdateQueue = currentlyRenderingFiber.updateQueue;
  if (componentUpdateQueue === null) {
    componentUpdateQueue = createFunctionComponentUpdateQueue();
    currentlyRenderingFiber.updateQueue = componentUpdateQueue;
    componentUpdateQueue.lastEffect = effect.next = effect;
  } else {
    const lastEffect = componentUpdateQueue.lastEffect;
    if (lastEffect === null) {
      componentUpdateQueue.lastEffect = effect.next = effect;
    } else {
      const firstEffect = lastEffect.next;
      lastEffect.next = effect;
      effect.next = firstEffect;
      componentUpdateQueue.lastEffect = effect;
    }
  }
  return effect;
}
function createFunctionComponentUpdateQueue() {
  return {
    lastEffect: null
  }
}

packages/react-reconciler/src/ReactFiberFlags.js

js
export const Passive = 0b00000000000000010000000000;

packages/react-reconciler/src/ReactHookEffectTags.js

js
export const NoFlags = 0b0000;
export const HasEffect = 0b0001;
export const Layout = 0b0100;
export const Passive = 0b1000;

基于 VitePress 构建