为什么useEffect不适合进行API调用


作者丨Rojan Maharjan
译者 | 涂承烨
React团队在useEffect钩子中做出的设计选择仍然是一个热议的话题。有些人喜欢,有些人不喜欢。
如果你不是来自React世界,这听起来肯定很奇怪,因为它的默认行为是非常容易遇到的可怕的“无限渲染循环”。例如:
useEffect(()=>{console.log("Hello?World")})
看起来很好,对吧?
不,这将在每次渲染中打印“Hello World”,React dev模式下强迫症的我会迫不及待地将结果放置到第二个参数的依赖数组中,像这样:
useEffect(()=>{console.log("Hello?World")},[])
左右滑动查看完整代码
因此,我们必须始终手动确保每次使用它时不会陷入无限循环。
就这样,我们修复了这个问题,上面的代码应该只运行一次,对吗?
技术上来说,但并不总是如此……

严格模式问题
在开发模式下,如果你想享受React严格模式的好处,这实际上会被调用两次。
你已经知道为什么这是一个问题了。以下面的代码为例:
useEffect(()=>{
api.post("/view",{})
},[])
假设我们有一个代码,它发送一个事件,说用户像上面的useEffect一样查看了页面。在严格模式下,React将运行这个效果两次,并发送一个双重事件。
你可以让hacky参考下面这样来工作:
export?default?function?useEffectOnce(fn:?()?=>?void)?{
const?ref?=?useRef(false);
useEffect(()?=>?{
if?(ref.current)?{
fn();
}
return?()?=>?{
ref.current?=?true;
};
},?[fn]);
}
左右滑动查看完整代码
但从本质上说,这是一个问题,至少不是一个优雅的解决方案。

性能问题
根据官方文档,useEffect钩子在整个UI或组件渲染完成后运行。因此,当我们在其中放入一个API调用时,API调用将在UI完成完整呈现后启动,如下所示:

这并不是最优的,因为尽管react是快速的,但渲染UI总是会消耗一些时间,它将延迟我们的API调用,而这也可以在渲染开始时运行。
因此,更好的方法是获取数据且并行渲染它。
我们该怎么做呢?

React查询来解决
React query和我们讨论的完全一样,像useQuery这样的钩子会在渲染开始时立即获取数据,所以你不必等待React加载完整个组件,如下所示:

下面是一个例子:
//?with?react?query
const?{?status,?data,?error,?isFetching?}?=?useQuery(
['data'],
async?()?=>?{
const?data?=?await?(
await?fetch(`${API_BASE_URL}/data`)
).json()
return?data
}
)//?without?react?query
useEffect(()?=>?{
try?{
setLoading(true)(async?()?=>?{
const?data?=?await?(await?fetch(`${API_BASE_URL}/data`)).json();
setData(data);
})();
}?catch?(error)?{
setError(error);
}?finally?{
setLoading(false);
}
},?[]);
左右滑动查看完整代码
通过查看语法,我们可以看到react query不仅在页面加载时立即执行query,而且还在react query返回的单个对象中处理许多事情,如加载状态、错误状态和实际数据。
此外,重新运行/使查询无效很简单,如下所示。
queryClient.invalidateQueries(['data'])
其他一些著名的库也解决了这些问题,如SWR、URQL和Apollo Client。
解决该问题的另一种方法是执行SSR,以便数据先在后端渲染,或者使用react-router 加载器等功能。

结论
对useEffects进行API调用可能很容易出错或非常慢。所以,除非不得已,否则最好避免使用。同时,建议你通过一些库来处理数据的获取更为合适。
涂承烨,51CTO社区编辑,信息系统项目管理师、信息系统监理师、PMP,某省综合性评标专家,拥有15年的开发经验。对项目管理、前后端开发、微服务、架构设计、物联网、大数据等较为关注。


关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 习近平将发表二〇二六年新年贺词 7904141
- 2 2026年国补政策来了 7808738
- 3 东部战区:开火!开火!全部命中! 7712893
- 4 2026年这些民生政策将惠及百姓 7616985
- 5 小学食堂米线过期2.5小时被罚5万 7519709
- 6 解放军喊话驱离台军 原声曝光 7428214
- 7 为博流量直播踩烈士陵墓?绝不姑息 7327605
- 8 每月最高800元!多地发放养老消费券 7238391
- 9 数字人民币升级 1月1日起将计付利息 7141831
- 10 2026年1月1日起 一批新规将施行 7040675








51CTO技术栈
