React 的 useEffect
是用于处理副作用(如数据获取、订阅、手动 DOM 操作等)的 Hook。以下是几个常见使用场景的示例:
1. 组件挂载时获取数据
jsx
import { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// 定义一个异步函数
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
// 清理函数(可选,比如取消请求)
return () => {
// 可以在这里取消未完成的请求
};
}, []); // 空依赖数组:仅在组件挂载时运行一次
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
{data.map(item => <div key={item.id}>{item.name}</div>)}
</div>
);
}
2. 依赖项触发副作用
当某个值(如 count
)变化时更新文档标题:
jsx
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // 依赖项为 count,当 count 变化时触发
return (
<button onClick={() => setCount(count + 1)}>
Increment ({count})
</button>
);
}
3. 添加和移除事件监听器
监听窗口大小变化:
jsx
function WindowSizeTracker() {
const [windowSize, setWindowSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener('resize', handleResize);
// 清理函数:组件卸载时移除事件监听
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // 空依赖数组:仅在组件挂载和卸载时运行
return (
<div>
Window size: {windowSize.width} x {windowSize.height}
</div>
);
}
4. 定时器(setInterval)
每秒更新一次时间:
jsx
function Timer() {
const [time, setTime] = useState(new Date());
useEffect(() => {
const timerId = setInterval(() => {
setTime(new Date());
}, 1000);
// 清理函数:组件卸载时清除定时器
return () => clearInterval(timerId);
}, []); // 空依赖数组:定时器只初始化一次
return <div>Current time: {time.toLocaleTimeString()}</div>;
}
5. 依赖项为空 vs 无依赖
- 空依赖数组
[]
:仅在组件挂载时运行一次。 - 无依赖数组:每次组件渲染后都会运行。
- 特定依赖
[dep1, dep2]
:当依赖项变化时运行。
注意事项
-
避免无限循环 :如果依赖项是引用类型(如对象或数组),需确保它们的引用稳定(比如使用
useMemo
)。 -
异步操作 :直接在
useEffect
中使用async
函数会报错,但可以在内部定义async
函数并调用:jsxuseEffect(() => { const fetchData = async () => { /* ... */ }; fetchData(); }, []);
-
清理副作用:始终为需要清理的操作(如事件监听、定时器)返回清理函数。
通过合理使用 useEffect
,可以管理组件的生命周期和副作用逻辑。