在React函数组件中,useEffect是数据获取的核心工具,但处理不当容易引发内存泄漏和状态错误。以下关键实践可帮你避开常见陷阱:
1. 使用AbortController取消请求
useEffect(() => {
const abortController = new AbortController();
const fetchData = async () => {
try {
const response = await fetch('/api/data', {
signal: abortController.signal
});
setData(await response.json());
} catch (e) {
if (e.name !== 'AbortError') {
// 处理真实错误
}
}
};
fetchData();
return () => abortController.abort(); // 组件卸载时中断请求
}, []);
2. 处理异步竞态条件
useEffect(() => {
let isActive = true; // 有效性标志
fetch(`/api/user/${
userId}`)
.then(res => res.json())
.then(data => {
if (isActive) setUser(data); // 仅当组件仍挂载时更新
});
return () => {
isActive = false }; // 清理函数更新标志
}, [userId]); // 依赖userId变化
3. 避免直接使用async函数
错误做法:
// 错误!清理函数无法正常工作
useEffect(async () => {
const data = await fetchData();
setState(data);
}, []);
正确做法:
useEffect(() => {
let isMounted = true;
const loadData = async () => {
const data = await fetchData();
if (isMounted) setState(data);
};
loadData();
return () => {
isMounted = false };
}, []);
关键总结
- 所有网络请求必须通过
AbortController可取消 - 使用
isActive标志防止已卸载组件的状态更新 - 避免将
useEffect回调直接设为async函数 - 依赖数组需包含所有变化值(ESLint规则可辅助检测)
遵循这些模式可显著提升应用稳定性,避免“内存泄漏”警告和状态更新混乱。记住:每个数据请求都需要明确的终止机制!