React中使用Faker API循环获取不同图片URL的问题及无限渲染困扰
解决Faker API循环获取同一张图片的问题
问题场景
我想通过循环调用Faker API获取4张不同的时尚图片,但目前所有<img>标签都使用同一个URL;尝试用state变量触发useEffect重新请求时,又会导致组件无限渲染。
原逻辑代码:
var change = 1 useEffect(() => { async function get() { setloading(true) const i = await faker.image.fashion(120, 200) setimg(i) console.log(img) setloading(false) } get() }, [change])
对应的JSX渲染代码:
<div className='box'> <h3>Latest Trends</h3> <div className='details'> {loading ? <ClipLoader color='#000000' loading={!loading} cssOverride={override} size={30} /> : [1, 2, 3, 4].map(e => { change = change + 1 console.log(change); return ( <div className='img'> <img src={img} alt="" /> </div> ) })} </div> </div>
尝试用state修改change时出现无限渲染:
[1, 2, 3, 4].map(e => { setchange(change + 1) console.log(change); return ( <div className='img'> <img src={img} alt="" /> </div> ) })
问题原因
- 普通变量无法触发组件更新:修改普通变量
change不会触发React重新渲染,useEffect不会执行新的请求,img状态始终是第一次请求的结果,循环里复用自然都是同一张图。 - render中调用
setState触发死循环:在map循环里调用setchange,每次组件渲染都会触发状态更新,进而再次触发渲染,陷入无限循环。
解决方案
核心思路是一次性获取4张图片的URL并存储为数组状态,避免反复触发渲染或复用单一URL。
方案1:同步生成4张图片URL(适用于Faker方法为同步的情况)
import { useState, useEffect } from 'react'; import { ClipLoader } from 'react-spinners'; const TrendComponent = () => { const [loading, setLoading] = useState(true); const [images, setImages] = useState([]); useEffect(() => { // 一次性生成4个独立的图片URL const generateImages = () => { const newImages = []; for (let i = 0; i < 4; i++) { newImages.push(faker.image.fashion(120, 200)); } setImages(newImages); setLoading(false); }; generateImages(); }, []); return ( <div className='box'> <h3>Latest Trends</h3> <div className='details'> {loading ? ( <ClipLoader color='#000000' loading={loading} cssOverride={override} size={30} /> ) : ( images.map((imgUrl, index) => ( <div key={index} className='img'> <img src={imgUrl} alt={`时尚单品 ${index + 1}`} /> </div> )) )} </div> </div> ); }; export default TrendComponent;
方案2:异步并行获取4张图片(适用于Faker方法为异步的情况)
如果Faker的图片接口是异步返回Promise,可通过Promise.all并行处理所有请求:
import { useState, useEffect } from 'react'; import { ClipLoader } from 'react-spinners'; const TrendComponent = () => { const [loading, setLoading] = useState(true); const [images, setImages] = useState([]); useEffect(() => { const fetchImages = async () => { setLoading(true); // 创建4个异步请求的Promise实例 const imagePromises = Array.from({ length: 4 }, () => faker.image.fashion(120, 200) // 假设此方法返回Promise ); // 并行等待所有请求完成 const newImages = await Promise.all(imagePromises); setImages(newImages); setLoading(false); }; fetchImages(); }, []); return ( <div className='box'> <h3>Latest Trends</h3> <div className='details'> {loading ? ( <ClipLoader color='#000000' loading={loading} cssOverride={override} size={30} /> ) : ( images.map((imgUrl, index) => ( <div key={index} className='img'> <img src={imgUrl} alt={`时尚单品 ${index + 1}`} /> </div> )) )} </div> </div> ); }; export default TrendComponent;
内容的提问来源于stack exchange,提问作者user19763623
相关产品推荐
相关产品推荐

