React 的 useEffect
钩子详解
useEffect
是 React 中最常用的 Hook 之一,它允许你在函数组件中执行副作用操作(side effects)。
基本概念
useEffect
是 React 16.8 引入的 Hook,用于在函数组件中处理副作用操作,如:
- 数据获取
- 订阅/事件监听
- 手动修改 DOM
- 设置定时器
基本语法
useEffect(() => {
// 副作用逻辑
return () => {
// 清除逻辑(可选)
};
}, [依赖项]);
三种主要使用方式
- 无依赖项 - 每次渲染后都执行
useEffect(() => {
console.log('每次渲染后执行');
});
- 空依赖数组 - 仅在组件挂载时执行一次
useEffect(() => {
console.log('仅在组件挂载时执行');
}, []);
- 带依赖项 - 依赖项变化时执行
useEffect(() => {
console.log('count变化时执行');
}, [count]);
常见应用场景
数据获取
useEffect(() => {
const fetchData = async () => {
const result = await axios('https://api.example.com/data');
setData(result.data);
};
fetchData();
}, []);
事件监听
useEffect(() => {
const handleResize = () => {
console.log('窗口大小改变');
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
定时器
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
清理机制
useEffect
可以返回一个清理函数,在以下时机执行:
- 组件卸载时
- 下一次副作用执行前(依赖项变化时)
useEffect(() => {
const subscription = source.subscribe();
return () => {
subscription.unsubscribe();
};
}, [source]);
注意事项
-
避免无限循环:当在
useEffect
中更新状态且该状态是依赖项时,可能导致无限循环 -
正确处理依赖项:确保依赖数组中包含所有在 effect 中使用的外部变量
-
性能优化:对于复杂计算,可以使用
useMemo
或useCallback
来避免不必要的 effect 执行 -
与
useLayoutEffect
的区别:useEffect
是异步执行的(不会阻塞浏览器渲染),而useLayoutEffect
是同步执行的
工作原理
- 调度阶段:React 将 effect 函数及其依赖项排队等待执行
- 提交阶段:React 完成 DOM 更新后执行 effect
- 清理机制:执行上一次渲染的清理函数(如果有)
- 执行 effect:运行当前 effect 函数
useEffect
的设计使得副作用不会阻塞浏览器渲染,确保了良好的用户体验。