跳到主要内容

用useEffect模拟WillUnMount时的注意事项

面试速答

  • 以下内容以 React 18 为准。
  • useEffect 模拟卸载逻辑,核心写法是“空依赖 + cleanup”:
useEffect(() => {
return () => {
// 清理逻辑
}
}, [])
  • 但真正高频考点不是写法本身,而是 cleanup 的时机、闭包值、StrictMode 行为和副作用取消

一、cleanup 不只在卸载时执行

很多人会背成“返回函数就是卸载执行”,这不完整。

更准确地说:

  • 组件卸载时会执行 cleanup
  • effect 重新执行前,也会先执行上一次 cleanup

只是当依赖数组是 [] 时,通常不会因为依赖变化重跑,所以表现得像只在卸载时执行。

二、React 18 开发环境会多跑一轮

StrictMode 下,首次挂载后可能经历:

  1. 执行 effect
  2. 执行 cleanup
  3. 再执行 effect

所以 cleanup 必须是幂等的,不能假设“只会执行一次”。

三、cleanup 里拿到的也是那一轮 render 的闭包

比如你在 cleanup 里打印某个值,它拿到的不是“卸载瞬间的全局最新值”,而是创建这个 effect 时那一轮 render 的快照。

如果你必须读最新值,通常要配合 useRef

四、清理的不只是事件

真实项目里要清理的常见对象包括:

  • DOM 监听
  • 定时器
  • WebSocket / 订阅
  • 第三方实例
  • 异步请求竞态标记

比如请求场景里常见写法:

useEffect(() => {
let cancelled = false

loadData().then(data => {
if (!cancelled) {
setData(data)
}
})

return () => {
cancelled = true
}
}, [])

五、不要在 cleanup 里滥做状态更新

cleanup 的目的通常是撤销副作用,不是再发起新的业务更新。尤其组件已经卸载时,再更新本组件状态没有意义。

标准答法

问:用 useEffect 模拟 componentWillUnmount 有什么注意点?

答:要知道 cleanup 不只在卸载时执行;React 18 开发环境会额外跑一轮;cleanup 读到的是创建它那一轮的闭包;同时要把事件、定时器、订阅和异步竞态都清干净。

易错点

  • 认为 cleanup 只在卸载触发。
  • 忽略 StrictMode 的额外执行。
  • cleanup 里还在依赖“最新状态”却没处理闭包问题。

速记要点

  • return 出来的函数是 cleanup。
  • cleanup 在重跑前和卸载时都会执行。
  • 重点是清理彻底且幂等。