React使用useState为遍历渲染的每个图片单独设置加载占位图的问题
问题核心原因
你当前定义的imageLoaded是全局共享的单个布尔状态,所有遍历渲染的图片都绑定同一个状态判断,自然只要任意一张图片加载完成触发setImageLoaded(true),所有图片的loading占位都会同时消失。
解决方案
方案1:在当前组件内用集合存储已加载图片标识
用Set存储所有加载完成的图片唯一ID(这里你用的是item.edition作为唯一key,直接复用即可):
- 修改状态定义:
// 存储所有已加载完成的图片edition const [loadedEditions, setLoadedEditions] = useState(new Set());
- 修改渲染逻辑:
<div className="row"> {shownImages.map((item) => ( <div className="images-col" key={item.edition}> <div style={{ cursor: 'pointer' }} onClick={() => onPressImage(item.edition)}> <div className="img-container"> <ul key={item.edition}> <li className="imgPlaceholder"> {/* 只判断当前图片的edition是否在已加载集合里 */} {loadedEditions.has(item.edition) ? null : <img alt="" src="images/loading.gif"></img>} <img style={loadedEditions.has(item.edition) ? {} : { display: 'none' }} onLoad={() => { // 加载完成后把当前edition加入已加载集合 setLoadedEditions(prev => { const newSet = new Set(prev); newSet.add(item.edition); return newSet; }) }} src={"https://imagelink.com/" + item.imagelink.split("/").reverse()[0]} /> </li> </ul> </div> </div> </div> ))} </div>
方案2(更推荐):抽离独立图片组件
把单个图片卡片封装成独立组件,每个组件自己维护自身的加载状态,逻辑更清晰,互不干扰:
- 定义独立ImageCard组件:
const ImageCard = ({ item, onPressImage }) => { // 每个图片自己维护加载状态 const [isLoaded, setIsLoaded] = useState(false); return ( <div className="images-col"> <div style={{ cursor: 'pointer' }} onClick={() => onPressImage(item.edition)}> <div className="img-container"> <ul> <li className="imgPlaceholder"> {isLoaded ? null : <img alt="" src="images/loading.gif"></img>} <img style={isLoaded ? {} : { display: 'none' }} onLoad={() => setIsLoaded(true)} src={`https://imagelink.com/${item.imagelink.split("/").reverse()[0]}`} /> </li> </ul> </div> </div> </div> ) }
- 父组件直接调用:
<div className="row"> {shownImages.map(item => ( <ImageCard key={item.edition} item={item} onPressImage={onPressImage} /> ))} </div>
计数逻辑报错说明
Cannot create property 'current' on number '0'报错是因为你把普通数字变量当成useRef返回的ref对象使用了,如果你要统计加载总数需要用const loadCount = useRef(0)来定义计数器。不过计数逻辑只能实现所有图片加载完成后才统一隐藏所有loading,不符合你单张图片独立控制的需求。
内容的提问来源于stack exchange,提问作者Molly Hatchet
相关产品推荐
相关产品推荐

