Hooks

72 阅读2分钟

hooks

作用于函数组件, 所以我们看一下对于函数组件是怎么渲染的

  • 初次渲染:
  1. prepareToReadContext
  2. 从fiber对象上获取memoizedState, 这个属性包含了所有hooks的状态,是一个链表结构;
  3. 获取第一个hooks对象,currentHook
  4. let children = Component(props) // 执行函数组件 const ref = useRef(null)
function useRef(initialValue){
    // 1. 创建一个 hook 对象
    const hook = {
        memoizedState: null, // ref的值: {current: initialValue} 
        baseState: null,
        baseQueue: null,
        queue: null,
        next: null, // 指向下一个hook
    }
    const ref = {current: initialValue}

    // 2. 绑定到fiber对象的memoizedState上(状态,组件更新的时候也可以拿到这个状态)
    currentlyRenderingFiber.memoizedState = hook
    return ref;

    // 3. 如果是更新阶段进来,直接返回 hook.memoizedState
}

const cb = useCallback(() => {}, [])

function useCallback(callback, deps) {
    // 1. 创建 hook 对象
    const hook = {
        memoizedState: null, // [callback, deps]
    
        baseState: null,
        baseQueue: null,
        queue: null,
    
        next: null,
    };
    // 2. 更新阶段,依赖对比
    const nextDeps = deps
    const prevState = hook.memoizedState
    const prevDeps = prevState[1]

    if (prevState !== null) {
      if (nextDeps !== null) {
        if (areHookInputsEqual(nextDeps, prevDeps)) return prevState[0]
      }
    }
    hook.memoizedState = [callback, deps]
    return callback
}

const res = useMemo(() => 'demo', [])
和 useCallback 其实是一样的,只不过存的值是函数的返回值

const [val, setVal] = useState(null)

function useState(initialState) {
    // 1. 创建 hook 对象
    const hook = {
        memoizedState: null, 
        baseState: null,
        baseQueue: null,
        queue: null,
        next: null, // 指向下一个hook
    }
    if (typeof initialState === 'function') initialState = initialState()
    // 2. 保存 state 的值
    hook.memoizedState = hook.baseState = initialState;
    // 3. 更新队列,批量更新用的
    hook.queue = { /* ... */}

    // 4. 往queue中塞入一个更新,通知react重新渲染
    const dispatch = dispatchSetState.bind(
      null,
      currentlyRenderingFiber,
      queue,
    )

    return [hook.memoizedState, dispatch]
    // 因为fiber对象保存了组件状态,所以更新时就能拿到这个queue去遍历做state的更新,返回最新的hook.memoizedState
}

useEffect(() => {}, [])

function mountEffectImpl(fiberFlags, hookFlags, create, deps) {
    // flag标记 useEffect 和 useLayoutEffect
    const hook = mountWorkInProgressHook() // 创建 hook 对象
    const nextDeps = deps
    // 副作用标记
    currentlyRenderingFiber.flags |= fiberFlags
    // effect 对象(依赖,回调,销毁回调,next)
    const effect = {
        tag,
        create,
        destroy,
        deps,
        // Circular
        next,
    }
    hook.memoizedState = pushEffect(
      HookHasEffect | hookFlags,
      create,
      undefined,
      nextDeps,
    )

    // 最终 effect 会形成一个环形链表,保存在fiber上,在react的生命周期执行阶段执行
}