为什么useEffect里更新状态会无限循环?

轩辕秀玲 阅读 41

我在用useEffect做API请求时,按教程把依赖项设为空数组,但状态更新后页面一直刷新…

比如这样写:

useEffect(() => {
  fetchUsers().then(data => {
    setUsers(data);
  });
}, []);

然后在组件里用了users数据渲染列表,但页面卡死了,控制台没报错。如果把依赖项改成[users],反而会无限循环,出现”Too many re-renders”错误。之前在类组件用componentDidMount没问题,换成Hooks就搞不定,到底哪里错了?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
设计师爱慧
这个问题是React Hooks的经典坑,官方文档其实讲得很清楚但容易被忽略。你的两种写法都不太对:

第一种空数组依赖的问题是:虽然避免了重复执行,但如果fetchUsers函数定义在组件内部,ESLint会警告说缺少依赖(如果没配ESLint就默默出bug)

第二种[users]的写法会死循环是因为:每次setUsers都会改变users,触发useEffect重新执行,然后继续setUsers...无限套娃

推荐的做法是分两种情况:
1. 如果是纯组件内逻辑,确实只需要执行一次,就用空数组+关掉ESLint警告:
useEffect(() => {
fetchUsers().then(setUsers);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);


2. 更规范的做法是把fetchUsers放到useCallback里:
const fetchUsers = useCallback(async () => {
const res = await axios.get('/api/users');
setUsers(res.data);
}, []);

useEffect(() => {
fetchUsers();
}, [fetchUsers]);


顺便吐槽下,React文档里这个useEffect的依赖数组机制确实反直觉,我刚开始用的时候也踩过这个坑,后来发现只要记住:所有useEffect里用到的变量都得放进依赖数组就对了。
点赞 3
2026-03-08 10:01
Designer°乙涵
你这个情况我太熟悉了,刚用Hooks那会儿我也被坑过。

首先空依赖数组 [] 是对的,表示只在组件挂载时执行一次,相当于类组件的 componentDidMount。你页面卡死但没报错,大概率不是无限循环,而是请求数据后更新了状态,导致组件重新渲染——这是正常行为。但如果卡死,可能是你的 fetchUsers 本身有副作用,比如又触发了其他状态更新,或者API一直pending没返回,先检查下网络面板看请求是否完成。

真正会导致无限循环的是你后面说的把依赖写成 [users]。因为 useEffect 依赖 users,而你在里面调 setUsers 改变 users,每次更新都会重新触发这个 effect,于是不断请求、不断更新,直接爆栈,所以 React 报 "Too many re-renders"。

解决办法就是:API调用这种只需要执行一次的操作,就老老实实用空依赖数组 [],确保它只跑一次。如果真需要依赖某个变量,记得判断清楚会不会形成“改状态 → 触发effect → 改状态”的闭环。

还有个常见坑是:如果你的 fetchUsers 是在组件内部定义的函数,每次渲染都会重新创建,就算写了 [],也可能因为闭包问题拿不到最新数据。建议用 useCallback 包一下,或者直接在 useEffect 里内联请求逻辑。

简单粗暴版:

useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []); // 就用空数组,别乱加依赖


这样就没问题。先确认是不是请求本身卡住了,而不是循环。
点赞 10
2026-02-10 13:03