简单来说,useEffect 是 React 函数组件中用来处理副作用 (Side Effects) 的钩子。
你可以把它理解为"组件与外部世界沟通的桥梁"。
组件的核心任务是渲染 (把数据变成 UI),这是一个纯净的计算过程。但有时候你需要做一些"不纯净"的事情,比如:
- 去服务器拿数据。
- 手动改一下网页标题。
- 设置一个定时器。
- 监听鼠标滚动。
这些事情都不能在渲染过程中直接做,必须交给 useEffect 在渲染结束后去做。
它的三个核心作用(对应类组件的生命周期)
如果你熟悉 React 类组件,useEffect 相当于 componentDidMount、componentDidUpdate 和 componentWillUnmount 这三个生命周期的组合体。
1. 组件挂载时执行 (Mount)
"组件刚出现时,做点什么。"
比如:页面一加载就请求 API,或者建立 WebSocket 连接。
JavaScript
useEffect(() => {
console.log('组件挂载了(只运行一次)');
fetchData();
}, []); // ✅ 空数组:代表没有任何依赖,只在出生时跑一次
2. 依赖更新时执行 (Update)
"当某个数据变了,做点同步工作。"
这是 useEffect 最核心的设计理念:同步。保持组件内部状态和外部系统同步。
JavaScript
useEffect(() => {
console.log('userId 变了,我要重新获取用户信息');
fetchUserInfo(userId);
}, [userId]); // ✅ 依赖数组:只要 userId 变,我就重跑
3. 组件卸载/清理时执行 (Unmount / Cleanup)
"组件要消失了(或者依赖变了),把之前的烂摊子收拾一下。"
比如:清除定时器、取消订阅、断开连接,防止内存泄漏。
JavaScript
useEffect(() => {
const timer = setInterval(() => console.log('Tick'), 1000);
// 👇 返回一个清理函数
return () => {
clearInterval(timer);
console.log('组件卸载了,或者下次 Effect 运行前,先清理旧的定时器');
};
}, []);
总结一张表
| 写法 | 含义 | 对应类组件生命周期 |
|---|---|---|
useEffect(() => { ... }) |
每次渲染后都跑 | componentDidMount + componentDidUpdate |
useEffect(() => { ... }, []) |
只在第一次渲染后跑 | componentDidMount |
useEffect(() => { ... }, [prop]) |
只在 prop 变化后跑 | componentDidUpdate (带判断) |
useEffect(() => { return () => ... }, []) |
组件销毁时跑 | componentWillUnmount |
一句话心法
useEffect 的作用是告诉 React: "等把界面画好之后,去帮我做这件这件额外的事(副作用)。如果我依赖的变量变了,记得重做一遍。"