Next.js 13.4:FakeStore API分类加载骨架屏失效求解决方案
Next.js 13.4 分类加载骨架屏不显示问题解决方法
问题原因
你在组件目录创建的loading.js是Next.js App Router路由页面专属的加载组件,仅对路由段生效,普通组件无法通过这个文件触发加载状态。要给Categories组件添加加载骨架屏,需用Suspense配合自定义骨架屏实现。
简单可行的实现步骤
1. 把Categories改成异步Server Component
首先确保Categories组件是异步的,内部直接用fetch获取FakeStore分类数据:
// @/components/Categories.jsx async function getCategories() { // 添加cache: 'no-store'禁用缓存,每次访问都重新加载数据 const res = await fetch('https://fakestoreapi.com/products/categories', { cache: 'no-store' }); if (!res.ok) throw new Error('加载分类失败'); return res.json(); } export default async function Categories() { const categories = await getCategories(); return ( <div className="categories-grid"> {categories.map((category) => ( <div key={category} className="category-card"> <h3>{category}</h3> </div> ))} </div> ); }
2. 在Home组件中用Suspense配置骨架屏
替换原来的Suspense fallback内容,改成模拟分类卡片的骨架结构,并添加样式:
修改Home组件中的Suspense部分:
<section className={styles.sectionCategories}> <Suspense fallback={ <div className={styles.skeletonContainer}> {/* 生成4个占位卡片,对应分类数量 */} {[1,2,3,4].map((id) => ( <div key={id} className={styles.skeletonCard}></div> ))} </div> }> <Categories /> </Suspense> </section>
在home.module.scss中添加骨架屏样式:
.skeletonContainer { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; } .skeletonCard { background: #f0f0f0; border-radius: 8px; padding: 1.5rem; min-height: 80px; position: relative; overflow: hidden; // 添加渐变动画模拟加载动效 &::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent); animation: loading 1.5s infinite; } } @keyframes loading { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
3. 可选:抽离骨架屏组件复用
如果多个页面需要用到分类骨架屏,可单独抽成组件:
// @/components/SkeletonCategory.jsx import styles from './SkeletonCategory.module.scss'; export default function SkeletonCategory() { return ( <div className={styles.skeletonContainer}> {[1,2,3,4].map((id) => ( <div key={id} className={styles.skeletonCard}></div> ))} </div> ); }
之后在Home组件中导入使用:
import SkeletonCategory from '@/components/SkeletonCategory'; // ... <Suspense fallback={<SkeletonCategory />}> <Categories /> </Suspense>
注意事项
Categories必须是异步Server Component(使用async/await),否则Suspense不会触发加载状态- 如果
Categories是Client Component,需要手动用useEffect+useState管理加载状态:'use client'; import { useState, useEffect } from 'react'; export default function Categories() { const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { async function fetchData() { const res = await fetch('https://fakestoreapi.com/products/categories'); const data = await res.json(); setCategories(data); setLoading(false); } fetchData(); }, []); if (loading) { return <div className={styles.skeletonContainer}>...</div>; } return <div>...</div>; }
内容的提问来源于stack exchange,提问作者ivan kovba
相关产品推荐
相关产品推荐

