用useEffect模拟WillUnMount时的注意事项
面试速答
- 以下内容以 React 18 为准。
- 用
useEffect模拟卸载逻辑,核心写法是“空依赖 + cleanup”:
useEffect(() => {
return () => {
// 清理逻辑
}
}, [])
- 但真正高频考点不是写法本身,而是 cleanup 的时机、闭包值、StrictMode 行为和副作用取消。
一、cleanup 不只在卸载时执行
很多人会背成“返回函数就是卸载执行”,这不完整。
更准确地说:
- 组件卸载时会执行 cleanup
- effect 重新执行前,也会先执行上一次 cleanup
只是当依赖数组是 [] 时,通常不会因为依赖变化重跑,所以表现得像只在卸载时执行。
二、React 18 开发环境会多跑一轮
StrictMode 下,首次挂载后可能经历:
- 执行 effect
- 执行 cleanup
- 再执行 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 在重跑前和卸载时都会执行。
- 重点是清理彻底且幂等。