Bootstrap

9.hooks源码(想知道Function Component是怎样保存状态的嘛)

人人都能读懂的react源码解析(大厂高薪必备)

9.hooks源码(想知道Function Component是怎样保存状态的嘛)

视频课程&调试demos

​ 视频课程的目的是为了快速掌握react源码运行的过程和react中的scheduler、reconciler、renderer、fiber等,并且详细debug源码和分析,过程更清晰。

​ 视频课程:

​ demos:

课程结构:

hook调用入口

​ 在hook源码中hook存在于Dispatcher中,Dispatcher就是一个对象,不同hook 调用的函数不一样,全局变量ReactCurrentDispatcher.current会根据是mount还是update赋值为HooksDispatcherOnMount或HooksDispatcherOnUpdate

ReactCurrentDispatcher.current = 
  current === null || current.memoizedState === null//mount or update
  ? HooksDispatcherOnMount
	: HooksDispatcherOnUpdate;  

const HooksDispatcherOnMount: Dispatcher = {//mount时
  useCallback: mountCallback,
  useContext: readContext,
  useEffect: mountEffect,
  useImperativeHandle: mountImperativeHandle,
  useLayoutEffect: mountLayoutEffect,
  useMemo: mountMemo,
  useReducer: mountReducer,
  useRef: mountRef,
  useState: mountState,
  //...
};

const HooksDispatcherOnUpdate: Dispatcher = {//update时
  useCallback: updateCallback,
  useContext: readContext,
  useEffect: updateEffect,
  useImperativeHandle: updateImperativeHandle,
  useLayoutEffect: updateLayoutEffect,
  useMemo: updateMemo,
  useReducer: updateReducer,
  useRef: updateRef,
  useState: updateState,
  //...
};

hook数据结构

​ 在FunctionComponent中,多个hook会形成hook链表,保存在Fiber的memoizedState的上,而需要更新的Update保存在hook.queue.pending中

const hook: Hook = {
  memoizedState: null,//对于不同hook,有不同的值
  baseState: null,//初始state
  baseQueue: null,//初始queue队列
  queue: null,//需要更新的update
  next: null,//下一个hook
};

下面来看下memoizedState对应的值

  • useState:例如,state的值

  • useReducer:例如,state的值

  • useEffect:在mountEffect时会调用pushEffect创建effect链表,就等于effect链表,effect链表也会挂载到fiber.updateQueue上,每个effect上存在useEffect的第一个参数回调和第二个参数依赖数组,例如,,effect就是{create:callback, dep:dep,…}

  • useRef:例如,memoizedState{current: 0}

  • useMemo:例如,等于

  • useCallback:例如,等于。保存函数,保存的执行结果

useState&useReducer

之所以把useState和useReducer放在一起,是因为在源码中useState就是有默认reducer参数的useReducer。

  • useState&useReducer声明

  • mount阶段

  • update阶段

  • 执行阶段

useEffect

  • 声明

  • mount阶段

  • update阶段

  • 执行阶段

useRef

​ sring类型的ref已经不在推荐使用,ForwardRef只是把ref通过传参传下去,createRef也是{current: any这种结构,所以我们只讨论function或者{current: any}的useRef

//createRef返回{current: any}
export function createRef(): RefObject {
  const refObject = {
    current: null,
  };
  return refObject;
}
//ForwardRef第二个参数是ref对象
let children = Component(props, secondArg);
  • 声明阶段

  • mount阶段

  • update阶段

useMemo&useCallback

  • 声明阶段

  • mount阶段

  • update阶段

function updateMemo(
  nextCreate: () => T,
  deps: Array | void | null,
): T {
  const hook = updateWorkInProgressHook();//获取hook
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;

  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps: Array | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖
        return prevState[0];//没变 返回之前的状态
      }
    }
  }
  const nextValue = nextCreate();//有变化重新调用callback
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

function updateCallback(callback: T, deps: Array | void | null): T {
  const hook = updateWorkInProgressHook();//获取hook
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;

  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps: Array | null = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {//浅比较依赖
        return prevState[0];//没变 返回之前的状态
      }
    }
  }

  hook.memoizedState = [callback, nextDeps];//变了重新将[callback, nextDeps]赋值给memoizedState
  return callback;
}