Next.js加载器仅显示首次加载,分页切换时不触发显示问题
Next.js SSR分页切换时loading.js不显示的解决方案
问题原因
Next.js App Router 中的 loading.js 仅在初始页面加载(如直接访问URL、硬刷新)时触发显示。当通过客户端分页组件使用router.push修改URL的page参数时,属于软导航,Next.js会在后台异步获取新数据,期间保留当前页面内容,不会自动触发loading.js的加载状态。
解决方案
方案1:给分页组件添加客户端加载状态
修改Pagi组件,使用useTransition跟踪导航加载状态,同时显示加载提示并禁用分页交互:
"use client" import { useState, useEffect, useTransition } from "react"; import { useRouter, useSearchParams } from 'next/navigation'; import {Pagination, PaginationItem, PaginationCursor} from "@nextui-org/react"; export default function Pagi({pages}) { // 从URL获取当前页码,避免初始状态与URL不一致 const searchParams = useSearchParams(); const initialPage = Number(searchParams.get('page')) || 1; const [page, setPage] = useState(initialPage); const router = useRouter(); const [isPending, startTransition] = useTransition(); useEffect(() => { // 用startTransition包裹导航,让React跟踪加载过程 startTransition(() => { router.push(`/orders?page=${page}`); }); },[page]); return ( <div className="mt-8"> {/* 加载状态提示 */} {isPending && ( <div className="mb-4 text-center text-blue-600"> 加载中,请稍候... </div> )} <Pagination isCompact showControls showShadow color="primary" page={page} total={pages} onChange={(newPage) => setPage(newPage)} isDisabled={isPending} // 加载时禁用分页,防止重复点击 /> </div> ); }
方案2:结合Suspense实现组件级加载状态
将数据获取逻辑拆分到独立的服务器组件,并用Suspense包裹,在数据加载时显示自定义fallback(可复用loading.js的内容):
- 创建独立的订单列表服务器组件:
// orders/OrdersList.js import CTable from './dataTable'; export default async function OrdersList({ page }) { const orders = await getData(page); return <CTable data={orders} />; }
- 修改
page.js,添加Suspense边界:
// orders/page.js import { Suspense } from 'react'; import OrdersList from './OrdersList'; import Pagi from './Pagi'; export default async function page({ searchParams }) { const currentPage = searchParams.page || 1; return ( <main className="flex min-h-screen flex-col items-center justify-between p-24"> <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex"> <Suspense fallback={ {/* 可直接复用loading.js的加载UI,或自定义样式 */} <div className="flex items-center justify-center h-64"> <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div> </div> }> <OrdersList page={currentPage} /> </Suspense> </div> <Pagi pages={10}/> </main> ) }
补充说明
- 方案1适合快速添加分页专属的加载提示,用户体验更聚焦;
- 方案2适合需要统一组件级加载状态的场景,可复用加载UI;
- 若希望完全复用
loading.js的页面级加载效果,可尝试router.refresh(),但该方法会触发服务器组件全量刷新,体验接近硬刷新,需谨慎使用。
内容的提问来源于stack exchange,提问作者imran
相关产品推荐
相关产品推荐

