Skip to content

整体思路

在一个函数式组件中其只存在一个 FiberNode (workInProgress) , 然后在函数组件初次渲染的时候 声明了多少了 hook,就会存在hook

栗子

js
const App = props => {
        // 添加一个 hook
        const [visible, setVisible] = React.useState(true)
        // 添加一个 hook
        const [num, setNum] = React.useState(1)

        const handleClickBtn = () => {
          // setVisible hook上添加一个 update
          setVisible(!visible)
        }
        // setNum hook上添加一个 update
        setNum(num + 1)
        // setNum hook上添加一个 update
        setNum(num + 1)

        return (
          <div>
            <button onClick={handleClickBtn}>切换</button>
          </div>
        )
      }

image

所以在函数式组件初次渲染的时候 其所有的Hook的声明已经完成,并按照单项链表的顺序添加到 workInProgress.memoizedState

依赖的变量

需要注意的是 Hooks 的渲染流程是在 beginWork 中

  • workInProgressHook

    跟workInProgress一样 是一个指向当前实例对象的属性

    这边指向的是当前 workInProgress 的 hook

    image

    js
    /**
     * beginWork 初次渲染的时候 有一个Hooks就生成一个 hook对象,然后按照链表的结构保存到 workInProgreee.memoizedState上
     *  然后再将workInProgressHook指向当前的 hook对象
     * @returns
     */
    function mountWorkInProgressHook(): Hook {
      const hook: Hook = {
        memoizedState: null,
    
        baseState: null,
        baseQueue: null,
        queue: null,
    
        next: null,
      };
      // 如果当前函数组件第一次初始化 Hooks
      if (workInProgressHook === null) {
        // This is the first hook in the list
        currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
      } else {
        // Append to the end of the list
        workInProgressHook = workInProgressHook.next = hook;
      }
      return workInProgressHook;
    }
    
    // 在Component执行完成后 
    
    /**
     * render函数式组件
     * @param {*} current
     * @param {*} workInProgress
     * @param {*} Component
     * @param {*} props
     * @param {*} secondArg
     * @param {*} nextRenderLanes
     * @returns
     */
    export function renderWithHooks<Props, SecondArg>(
      current: Fiber | null,
      workInProgress: Fiber,
      Component: (p: Props, arg: SecondArg) => any,
      props: Props,
      secondArg: SecondArg,
      nextRenderLanes: Lanes,
    ): any {
      renderLanes = nextRenderLanes;
      currentlyRenderingFiber = workInProgress;
      
      workInProgress.memoizedState = null;
      workInProgress.updateQueue = null;
      workInProgress.lanes = NoLanes;
    
        // 通过全局变量的方式缓存当前Hooks方法函数
        //  -- 初次渲染的时候 使用的是hook的 mountState 等方法
        //  -- 更新   的时候 使用的是hooks的 updateState 等方法
      ReactCurrentDispatcher.current =
          current === null || current.memoizedState === null
            ? HooksDispatcherOnMount
            : HooksDispatcherOnUpdate;
      
      // 执行函数式组件
      let children = Component(props, secondArg);
    
      // Check if there was a render phase update
      if (didScheduleRenderPhaseUpdateDuringThisPass) {
        let numberOfReRenders: number = 0;
        do {
          didScheduleRenderPhaseUpdateDuringThisPass = false;
          numberOfReRenders += 1;
          if (__DEV__) {
            // Even when hot reloading, allow dependencies to stabilize
            // after first render to prevent infinite render phase updates.
            ignorePreviousDependencies = false;
          }
    
          // Start over from the beginning of the list
          currentHook = null;
          workInProgressHook = null;
    
          workInProgress.updateQueue = null;
    
          ReactCurrentDispatcher.current = __DEV__
            ? HooksDispatcherOnRerenderInDEV
            : HooksDispatcherOnRerender;
    
          children = Component(props, secondArg);
        } while (didScheduleRenderPhaseUpdateDuringThisPass);
      }
    
      ReactCurrentDispatcher.current = ContextOnlyDispatcher;
    
      const didRenderTooFewHooks =
        currentHook !== null && currentHook.next !== null;
    
      renderLanes = NoLanes;
      currentlyRenderingFiber = (null: any);
    
      currentHook = null;
      workInProgressHook = null;
    
      didScheduleRenderPhaseUpdate = false;
    
      return children;
    }
  • ReactCurrentDispatcher.current

    js
    // 通过全局变量的方式缓存当前Hooks方法函数
    //  -- 初次渲染的时候 使用的是hook的 mountState 等方法
    //  -- 更新   的时候 使用的是hooks的 updateState 等方法
    ReactCurrentDispatcher.current = current === null || current.memoizedState === null
      ? HooksDispatcherOnMount
      : HooksDispatcherOnUpdate;

    保存了在初次渲染 或者 更新 提供不同的执行方法

    image