深入 useEffect:依赖数组与闭包陷阱
依赖数组的真实语义、闭包陷阱的成因,以及清理函数的执行时序。
useEffect 是最常用也最容易被误解的 Hook。这一章我们把三个高频陷阱一次讲透。
## 闭包陷阱
```jsx
useEffect(() => {
const timer = setInterval(() => {
console.log(count); // 永远是初始值
}, 1000);
return () => clearInterval(timer);
}, []); // 依赖数组为空 = 闭包被冻结
```
依赖数组为空时,effect 捕获的是第一次渲染的变量。解法:用函数式更新 `setCount(c => c + 1)`,或把 `count` 加入依赖。
## 依赖数组不是“优化开关”
很多人把依赖数组当成“要不要执行”的开关,其实它是**同步声明**:effect 里用到的所有外部值,都应该出现在依赖里。少写一个依赖,不是省一次执行,而是埋一个过期数据。
## 清理函数的时序
1. 清理函数在下一次 effect 执行之前运行
2. 组件卸载时也会运行
3. 这就是为什么事件订阅、定时器必须在清理函数里释放
理解了这三点,useEffect 就从“玄学”变成了确定性工具。