美文网首页
七、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)

相关文章

  • 详解react useEffect 和 useLayoutEff

    useEffect 引用官方 使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件...

  • Hooks API

    useEffect useEffect的使用 参考上篇文章 执行时机: useEffect可以看做componen...

  • react hooks 之 useEffect

    useEffect useEffect 可以弥补函数组件没有生命周期的缺点。我们可以在useEffect第一个参数...

  • 从react源码分析useEffect与useLayoutEff

    本文将从useEffect的‘闪烁’问题切入,通过devtools并结合源码来分析useEffect与useLay...

  • useEffect

    目标 页面count会递增 console里面的数会递增 问题描述 页面上的count只会改变一次,即从0变为1 ...

  • useEffect

    副作用 对环境或全局变量的改变就是副作用,例如修改document.title,对自己state的改变不是副作用 ...

  • useEffect

    1. 基本使用 2. 存在依赖项 依赖项为一个空数组[]时只执行一次 只要有一个变化useEffect都会重复执行...

  • useEffect

    1.useEffect的特点1)有两个参数callback和dependencies数组;2)如果dependen...

  • useEffect

    useEffect的用法代替componentDidMount的方式,将useEffect的第二个参数传入空数组或...

  • useEffect

    使用useEffect完成副作用操作。赋值给useEffect的函数会在组件渲染到屏幕之后执行。 在函数组件主体内...

网友评论

      本文标题:七、useEffect

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