You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-loading-skeleton在组件中不显示问题求助

解决react-loading-skeleton加载时不显示的问题

问题根源分析

  1. isLoading状态提前终止:你在两个独立的异步请求中分别调用setIsLoading(false),只要其中一个请求完成,加载状态就会被关闭,另一个请求还在进行时骨架屏已经消失。
  2. 初始无数据时无骨架占位:shopCoupons初始为空数组,map不会渲染任何Coupon组件,所以即使isLoading为true,页面上也看不到骨架屏。
  3. Coupon组件部分区域未处理加载状态:图片和描述区域没有在加载时显示骨架屏,体验不完整。

具体修复方案

1. 同步两个异步请求的加载状态

使用Promise.all等待两个请求都完成后,再将isLoading设为false,确保所有数据加载完成后才关闭骨架屏。

2. 加载时渲染骨架占位

当isLoading为true时,渲染固定数量的骨架屏(模拟优惠券列表),而不是依赖shopCoupons的数据。

3. 完善Coupon组件的加载状态

给图片、描述区域也添加骨架屏,保证整个组件在加载时都有占位效果。

修改后的代码

ShopPage.jsx

import Skeleton from 'react-loading-skeleton'
import 'react-loading-skeleton/dist/skeleton.css'
import Coupon from "../../components/coupon/Coupon";
import { Box } from '@mui/material';

export default function ShopPage() {
  const [disable, setDisable] = useState(false);
  const [shop, setShop] = useState("");
  const shopName = useParams().shopName;
  const [shopCoupons, setCoupons] = useState([]);
  const { search } = useLocation();
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        // 同时发起两个请求,等待都完成
        const [shopRes, couponsRes] = await Promise.all([
          axios.get(`/shops/${shopName}`),
          axios.get(`/coupons/${shopName}`)
        ]);
        setShop(shopRes.data);
        setCoupons(couponsRes.data);
      } catch (err) {
        console.error('数据加载失败:', err);
      } finally {
        // 无论成功失败,都关闭加载状态
        setIsLoading(false);
      }
    };
    fetchData();
  }, [shopName]);

  return (
    <>
      <div className="ShopPage">
        <div className="ShopPageContainer">
          <div className="ShopPageInfoContainer">
            <div className="ShopPageShopNameButton">
              <div>
                <h5 className="ShopPageShopName">
                  {isLoading ? <Skeleton /> : `${shop.shopName} `}
                </h5>
              </div>
            </div>
          </div>

          <Box className="ShopPageCouponsContainer">
            {isLoading ? (
              // 加载时渲染3个骨架占位,数量可根据需求调整
              Array.from({ length: 3 }).map((_, idx) => (
                <div key={idx} className="coupon-container">
                  <Skeleton height={120} borderRadius={8} />
                </div>
              ))
            ) : (
              shopCoupons.map(c => (
                <Coupon isLoading={isLoading} coupon={c} key={c.id}/>
              ))
            )}
          </Box>
        </div>
      </div>
    </>
  )
}

Coupon.jsx

import Skeleton from 'react-loading-skeleton'
import 'react-loading-skeleton/dist/skeleton.css'

export default function Coupon({ coupon, isLoading }) {
  return (
    <div className="coupon-container">
      <div className="coupon">
        <div className="co-img">
          {isLoading ? (
            <Skeleton circle width={60} height={60} />
          ) : (
            coupon.photo && <img className="couponLogo" src={coupon.shopPic} alt={coupon.shopName} />
          )}
        </div>
        <div className="content">
          <a href={`/shops/${coupon.shopName}`} target="_self">
            <h2 className="couponShopName">
              {isLoading ? <Skeleton width={150} /> : coupon.shopName}
            </h2>
          </a>
          <h1>{isLoading ? <Skeleton width={200} /> : coupon.title}</h1>
        </div>
        <div className="couponDesc">
          {isLoading ? <Skeleton count={2} /> : coupon.desc}
        </div>
      </div>
    </div>
  );
}

额外注意事项

  • key属性不要直接传递对象c,建议使用优惠券的唯一ID(比如c.id),避免React渲染警告。
  • 可以根据实际布局调整Skeleton的尺寸(width、height、count等属性),让骨架屏更贴近真实组件的样式。
  • 记得处理请求失败的情况,避免加载状态一直卡在true。

内容的提问来源于stack exchange,提问作者sultan.h

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:45:50