我在用useEffect做API请求时,按教程把依赖项设为空数组,但状态更新后页面一直刷新…
比如这样写:
useEffect(() => {
fetchUsers().then(data => {
setUsers(data);
});
}, []);
然后在组件里用了users数据渲染列表,但页面卡死了,控制台没报错。如果把依赖项改成[users],反而会无限循环,出现”Too many re-renders”错误。之前在类组件用componentDidMount没问题,换成Hooks就搞不定,到底哪里错了?
第一种空数组依赖的问题是:虽然避免了重复执行,但如果
fetchUsers函数定义在组件内部,ESLint会警告说缺少依赖(如果没配ESLint就默默出bug)第二种
[users]的写法会死循环是因为:每次setUsers都会改变users,触发useEffect重新执行,然后继续setUsers...无限套娃推荐的做法是分两种情况:
1. 如果是纯组件内逻辑,确实只需要执行一次,就用空数组+关掉ESLint警告:
2. 更规范的做法是把
fetchUsers放到useCallback里:顺便吐槽下,React文档里这个useEffect的依赖数组机制确实反直觉,我刚开始用的时候也踩过这个坑,后来发现只要记住:所有useEffect里用到的变量都得放进依赖数组就对了。
首先空依赖数组
[]是对的,表示只在组件挂载时执行一次,相当于类组件的componentDidMount。你页面卡死但没报错,大概率不是无限循环,而是请求数据后更新了状态,导致组件重新渲染——这是正常行为。但如果卡死,可能是你的fetchUsers本身有副作用,比如又触发了其他状态更新,或者API一直pending没返回,先检查下网络面板看请求是否完成。真正会导致无限循环的是你后面说的把依赖写成
[users]。因为useEffect依赖users,而你在里面调setUsers改变users,每次更新都会重新触发这个 effect,于是不断请求、不断更新,直接爆栈,所以 React 报 "Too many re-renders"。解决办法就是:API调用这种只需要执行一次的操作,就老老实实用空依赖数组
[],确保它只跑一次。如果真需要依赖某个变量,记得判断清楚会不会形成“改状态 → 触发effect → 改状态”的闭环。还有个常见坑是:如果你的
fetchUsers是在组件内部定义的函数,每次渲染都会重新创建,就算写了[],也可能因为闭包问题拿不到最新数据。建议用useCallback包一下,或者直接在useEffect里内联请求逻辑。简单粗暴版:
这样就没问题。先确认是不是请求本身卡住了,而不是循环。