7-2. 实现 cleanup

37 阅读1分钟

本节课我们来实现一下useEffect中的cleanUp,它会再调用useEffect之前调用,目的是清空所有副作用,当deps为空的时候不会调用cleanUp。

app.js

React.useEffect(() => {
    console.log('init')
    return () => {
      console.log("cleanup 0")
    }
  }, [])
​
​
  React.useEffect(() => {
    console.log('update1', count)
    return () => {
      console.log("cleanup 1")
    }
  }, [count])
​
  React.useEffect(() => {
    console.log('update2', count)
    return () => {
      console.log("cleanup 2")
    }
  }, [count])

cleanUp的存放,以及调用

  • react.js
function commitEffectHooks() {
    function run(fiber) {
        if (!fiber) {
            return
        }
​
        if(!fiber.alternate) {
            fiber?.effectHooks?.forEach((hook) => {
                hook.cleanup = hook.callback()
            })
        }else {
            // update
            // deps 有没有发生改变
            fiber.effectHooks?.forEach((newHook, index)=> {
                if(newHook.deps.length> 0 ) {
                    const oldEffectHook = fiber.alternate?.effectHooks[index]
​
                    // some
                    const needUpdate = oldEffectHook?.deps.some((oldDep, i) => {
                        return oldDep !== newHook.deps[i]
                    })
​
                    needUpdate && (newHook.cleanup = newHook.callback())
                }
            })
        }
​
        run(fiber.child)
        run(fiber.sibling)
    }
​
    function runCleanup (fiber) {
        if(!fiber) return
        fiber.alternate?.effectHooks?.forEach((hook) => {
            hook.cleanup && hook.cleanup()
        })
        runCleanup(fiber.child)
        runCleanup(fiber.sibling)
    }
    runCleanup(wipRoot)
    run(wipFiber)
}
​
​

1.png

处理依赖为空的情况

    function runCleanup (fiber) {
        if(!fiber) return
        fiber.alternate?.effectHooks?.forEach((hook) => {
            if(hook.deps.length > 0) {
                hook.cleanup && hook.cleanup()
            }
        })
        runCleanup(fiber.child)
        runCleanup(fiber.sibling)
    }

2.png