如何为从API拉取数据的React组件制作加载器,避免图片加载时布局错乱
实现方案
你的实现思路是可行的,我们可以在AlbumsList组件内新增加载状态,监听所有卡片关联图片的加载完成事件,全部资源加载完成后再隐藏加载Spinner,同时支持后续分批加载新数据时自动重置加载状态,适配非一次性加载的场景。
实现步骤
- 给组件添加两个状态:
isLoading控制Spinner显隐,loadedImagesCount统计已加载完成的图片数量 - 给
AlbumCard组件传入图片加载完成的回调函数,每一张图片加载完成后触发计数+1 - 当已加载计数等于当前渲染的卡片总数时,将
isLoading设为false,隐藏Spinner - Spinner用绝对定位放在列表容器的居中位置,加载阶段可以给列表加半透明遮罩或者占位样式,避免布局跳动
改造后完整代码
AlbumsList组件代码
import { useState, useEffect } from "react"; import AlbumCard from "../Cards/AlbumCard"; // 替换为你项目内的Spinner组件即可 import Spinner from "./Spinner"; const AlbumsList = (props) => { const [isLoading, setIsLoading] = useState(true); const [loadedImagesCount, setLoadedImagesCount] = useState(0); // 总卡片数量,随props.item更新自动同步 const totalCount = props.item?.length || 0; // 单张图片加载完成的回调 const handleImageLoad = () => { setLoadedImagesCount(prev => { const newCount = prev + 1; // 所有图片加载完成时关闭加载状态 if (newCount >= totalCount) { setIsLoading(false); } return newCount; }); }; // 分批加载新数据时自动重置加载状态 useEffect(() => { setIsLoading(true); setLoadedImagesCount(0); }, [props.item]); if (!totalCount) return null; return ( <div style={{ position: "relative", width: "100%" }}> {/* 加载中显示Spinner */} {isLoading && ( <div style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", zIndex: 10, }}> <Spinner /> </div> )} <ul style={{ position: "relative", padding: "0", display: "flex", flexWrap: "wrap", width: "100%", opacity: isLoading ? 0.3 : 1, transition: "opacity 0.2s ease", }} > {props.item.map((item) => ( <AlbumCard id={item.id} key={item.id} image={item.picture} artist={item.name} title={item.title} onImageLoad={handleImageLoad} /> ))} </ul> </div> ) } export default AlbumsList
AlbumCard组件修改说明
需要在AlbumCard内部的img标签上绑定onLoad事件,触发传入的回调即可,示例如下:
// AlbumCard组件内部img标签修改示例 <img src={image} alt={`${title} - ${artist}`} onLoad={onImageLoad} onError={onImageLoad} // 提前设置宽高可进一步避免布局偏移 width={200} height={200} style={{ objectFit: "cover" }} />
优化方案建议
- 可以给
AlbumCard提前设置固定宽高,或者使用卡片骨架屏占位,加载阶段显示骨架屏,比单纯显示Spinner的用户体验更好 - 如果图片资源体积较大,可添加图片懒加载逻辑,仅加载可视区域内的图片,提升页面加载速度
- 上述代码中已给img添加了
onError事件也触发加载回调,避免单张图片加载失败导致Spinner一直显示的问题
内容的提问来源于stack exchange,提问作者Francis
相关产品推荐
相关产品推荐

