使用Promise.all与useState触发无限循环的问题及解决方法
修复useState与Promise.all结合导致的无限循环问题
我用Promise.all获取一组URL数据的功能正常,但调用setLocationResidents(results)更新状态时触发了无限循环,该如何修复?
原代码:
const residentsUrl = [ 'https://rickandmortyapi.com/api/character/10', 'https://rickandmortyapi.com/api/character/81', 'https://rickandmortyapi.com/api/character/208', 'https://rickandmortyapi.com/api/character/226', 'https://rickandmortyapi.com/api/character/340', 'https://rickandmortyapi.com/api/character/362', 'https://rickandmortyapi.com/api/character/375', 'https://rickandmortyapi.com/api/character/382', 'https://rickandmortyapi.com/api/character/395' ] const [locationResidents, setLocationResidents] = useState([]) useEffect(() => { async function fetchAll() { const results = await Promise.all( residentsUrl?.map((url) => fetch(url).then((r) => r.json())) ); console.log("results", results); setLocationResidents(results); } fetchAll(); }, [residentsUrl, locationResidents]); <div> {locationResidents ?.map((location) => ( <div>{location.name}</div> ))} </div>
问题原因
你的useEffect依赖数组中包含了locationResidents状态,每次调用setLocationResidents都会更新这个状态,触发useEffect重新执行,进而再次调用setLocationResidents,形成无限循环。
修复方案
直接从useEffect的依赖数组中移除locationResidents即可,因为这个状态是useEffect内部更新的,不需要作为依赖项。
修改后的代码
const residentsUrl = [ 'https://rickandmortyapi.com/api/character/10', 'https://rickandmortyapi.com/api/character/81', 'https://rickandmortyapi.com/api/character/208', 'https://rickandmortyapi.com/api/character/226', 'https://rickandmortyapi.com/api/character/340', 'https://rickandmortyapi.com/api/character/362', 'https://rickandmortyapi.com/api/character/375', 'https://rickandmortyapi.com/api/character/382', 'https://rickandmortyapi.com/api/character/395' ] const [locationResidents, setLocationResidents] = useState([]) useEffect(() => { async function fetchAll() { const results = await Promise.all( residentsUrl?.map((url) => fetch(url).then((r) => r.json())) ); console.log("results", results); setLocationResidents(results); } fetchAll(); }, [residentsUrl]); // 移除locationResidents依赖 <div> {locationResidents ?.map((location) => ( <div>{location.name}</div> ))} </div>
额外优化(若URL数组动态变化)
如果residentsUrl是动态生成的(比如从props传入或其他状态计算而来),建议用useMemo缓存数组引用,避免因数组引用变化导致useEffect频繁触发:
import { useMemo } from 'react'; // 缓存动态生成的URL数组 const memoizedResidentsUrl = useMemo(() => { // 这里写动态生成数组的逻辑,比如处理props数据 return [/* 生成的URL数组 */]; }, [/* 依赖项:比如props中用于生成数组的值 */]); // useEffect依赖缓存后的数组 useEffect(() => { async function fetchAll() { const results = await Promise.all( memoizedResidentsUrl?.map((url) => fetch(url).then((r) => r.json())) ); setLocationResidents(results); } fetchAll(); }, [memoizedResidentsUrl]);
内容的提问来源于stack exchange,提问作者Ayse8888
相关产品推荐
相关产品推荐

