为何我的React组件中useEffect会触发无限循环?
React useEffect 无限循环问题解决:点击切换状态时更新数组
问题根源
你第三个useEffect的语法写错了!依赖数组[picked]被放在了useEffect的括号外面,导致这个Effect没有依赖列表——React会把没有依赖数组的Effect当成每次组件渲染都要执行的逻辑。每次执行它都会调用setImages,触发组件重新渲染,接着又执行这个Effect,无限循环就这么来了。
另外还有两个潜在问题:
- 第二个和第三个Effect都在修改
images状态,当dogs更新时会覆盖picked切换后的images值,逻辑会冲突 - 初始
dogs是空数组,直接取dogs[0]/dogs[1]/dogs[2]会导致数组越界报错
修复方案
1. 修正Effect语法错误
把第三个Effect的依赖数组放进正确的位置,同时加上dogs作为依赖(因为用到了它),还要判断数组长度避免报错:
useEffect(() => { if (dogs.length >= 3) { setImages([dogs[1], dogs[2]]); } }, [picked, dogs]);
2. 统一状态更新逻辑,避免冲突
调整逻辑,让dogs加载完成后初始化images,点击切换picked时再更新images,同时处理加载中的状态:
修改后的完整Game组件代码:
import GameCSS from './game.module.css' import Dog from "./dog/dog" import { useState, useEffect } from 'react' function Game () { const [dogs, setDogs] = useState<string[]>([]); const [picked, setPicked] = useState<boolean>(false); const [fave, setFave] = useState<string>(''); const [images, setImages] = useState<string[]>(); useEffect(() => { fetch('https://dog.ceo/api/breeds/image/random/10') .then(response => response.json()) .then(data => setDogs(data.message)); }, []); // 初始化images:dogs加载完成后设置初始图片 useEffect(() => { if (dogs.length >= 2) { setImages([dogs[0], dogs[1]]); } }, [dogs]); // 当picked切换时更新images useEffect(() => { if (dogs.length >= 3) { // 可根据picked状态灵活切换图片组,这里按你的需求实现 setImages(picked ? [dogs[1], dogs[2]] : [dogs[0], dogs[1]]); } }, [picked, dogs]); // 处理未加载完成的情况 if (!images) { return <div>Loading...</div> } return ( <> <div className={GameCSS.dogs}> <Dog image={images[0]} setFave={setFave} picked={picked} setPicked={setPicked} /> <Dog image={images[1]} setFave={setFave} picked={picked} setPicked={setPicked} /> </div> </> ) } export default Game
3. 额外优化
如果担心重复渲染,可以在更新images前加判断,比如对比当前值和要设置的值是否一致,不过上面的写法已经通过依赖数组控制了触发时机,基本够用。
验证效果
现在点击图片时,picked状态切换,第三个Effect会触发并更新images数组,组件重新渲染展示新的图片组合,不会再出现无限循环。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

