美文网首页
七、useEffect

七、useEffect

作者: sweetBoy_9126 | 来源:发表于2024-03-30 12:39 被阅读0次
    1. 实现初始化
      初始化加载 onMounted
      用法:
    useEffect(() => {
      console.log(1)
    }, [])
    

    实现:

    const useEffect = (callback, deps) => {
      const effectHook = {
        callback,
        deps
      }
      // 这里之所以用 wipFiber 因为它只有在每次有函数组件的时候才会调用,所以它肯定是一个函数组件
      wipFiber.effectHook = effectHook
    }
    

    因为我们要在 onMounted 里调用所以就要在节点都挂载完成的时候也就是我们的 commitWork 后

     const commitRoot = () => {
      deletions.forEach(commitDeletion)
      commitWork(wipRoot.child)
    +  commitEffectHooks()
       ...
    }
    
    const commitEffectHook = () => {
      const run = (fiber) => {
        if (!fiber) return
         fiber.effectHook?.callback()
        run(fiber.child)
        run(fiber.sibling)
      }
      // 这里不用 wipFiber 的原因是 wipFiber 每次会被覆盖,如果有多个函数组件那么只会执行最后一个的,所以我们需要从根节点开始逐层遍历
      run(wipRoot)
    }
    
    1. 实现 update
      用法:
      const [count, setCount] = React.useState(0)
      const handleClick = () => {
        setCount((count) => count + 1)
      }
      React.useEffect(() => {
        console.log(11111)
      }, [count])
    

    实现我们需要区分初始化和 update,这个我们可以通过我们的 alternate 指针来区分,没有就是初始化,然后需要对比老的新的依赖项的每一项和老的依赖项的对应的项值有没有变化,只要有一个值不一样我们就要重新调用

    const commitEffectHook = () => {
      const run = (fiber) => {
        if (!fiber) return
        if (!fiber.alternate) {
          // init
          fiber.effectHook?.callback()
        } else {
          // update
          const oldEffect = fiber.alternate?.effectHook
          const needUpdate = fiber.effectHook?.deps.some((dep, index) => {
            return dep !== oldEffect.deps[index]
          })
    
          needUpdate && fiber.effectHook?.callback()
        }
        run(fiber.child)
        run(fiber.sibling)
      }
    
      run(wipRoot)
    }
    
    1. 实现多个 useEffect
    let effectHooks
    
    const useEffect = (callback, deps) => {
      const effectHook = {
        callback,
        deps
      }
      effectHooks.push(effectHook)
      wipFiber.effectHooks = effectHooks
    }
    
    const commitEffectHooks = () => {
      const run = (fiber) => {
        if (!fiber) return
        if (!fiber.alternate) {
          // init
          fiber.effectHooks?.forEach(hook => hook?.callback())
        } else {
          // update
          fiber.effectHooks?.forEach((newHook, index) => {
            const oldEffect = fiber.alternate?.effectHooks[index]
            const needUpdate = newHook?.deps.some((dep, i) => {
              return dep !== oldEffect.deps[i]
            })
    
            needUpdate && newHook?.callback()
          })
        }
      
        run(fiber.child)
        run(fiber.sibling)
      }
    
      run(wipRoot)
    }
    
    1. 实现 cleanup
      1). 存下useEffect 返回的 cleanup 函数,也就是调用useEffect 的 callback 把返回值存下来
    const useEffect = (callback, deps) => {
      const effectHook = {
        callback,
        deps,
    +    cleanup: undefined
      }
      effectHooks.push(effectHook)
      wipFiber.effectHooks = effectHooks
    }
      const run = (fiber) => {
        if (!fiber) return
        if (!fiber.alternate) {
          // init
    +      fiber.effectHooks?.forEach(hook => (hook.cleanup = hook?.callback()))
        } else {
          // update
          fiber.effectHooks?.forEach((newHook, index) => {
            if (newHook.deps.length > 0) {
              const oldEffect = fiber.alternate?.effectHooks[index]
              const needUpdate = newHook?.deps.some((dep, i) => {
                return dep !== oldEffect.deps[i]
              })
    
    +          needUpdate && (newHook.cleanup = newHook?.callback())
            }
          })
        }
        
      }
    

    2). 在执行当前所有的 useEffect 之前调用

    +  const runCleanup = (fiber) => {
    +    if (!fiber) return
        // 取上一次的 effectHooks
    +    fiber.alternate?.effectHooks?.forEach(hook => {
          // [] 不应该执行
    +      if (hook.deps.length > 0) {
    +      hook.cleanup?.()
    +      }
    +    })
    +    runCleanup(fiber.child)
    +    runCleanup(fiber.sibling)
    +  }
    
    +  runCleanup(wipRoot)
      run(wipRoot)
    

    相关文章

      网友评论

          本文标题:七、useEffect

          本文链接:https://www.haomeiwen.com/subject/qexmtjtx.html