NextJS v14.2根目录loading.tsx仅单次生效,如何全局复用?
问题描述
我希望所有页面切换都回退使用目录层级较高的单个loading.tsx。我的Next.js v14.2项目结构如下:
app/ ├─ loading.tsx ├─ page.tsx ├─ child/ │ ├─ page.tsx │ ├─ grandchild/ │ │ ├─ page.tsx │ │ ├─ greatgrandchild/ │ │ │ ├─ page.tsx
目前根目录的loading.tsx仅能生效一次,后续页面导航时不会显示加载指示器。我当前的解决办法是在各个目录下都放置loading.tsx,但不想保留这些冗余文件,想知道Next.js是否支持始终回退使用高层级的loading.tsx。
可行方案
在Next.js的App Router中,默认的loading.tsx是路由段专属的——仅首次进入该路由段(或段内页面触发服务器组件重渲染)时才会触发对应层级的loading组件,后续同段内子页面导航不会重新触发父级loading。要实现全局复用根目录的loading.tsx,可采用以下两种方式:
1. 手动监听路由事件控制全局加载状态
在根布局app/layout.tsx中添加全局加载状态组件,通过监听路由变化显示/隐藏根目录的loading.tsx:
// app/layout.tsx 'use client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import Loading from './loading'; export default function RootLayout({ children }: { children: React.ReactNode }) { const [isLoading, setIsLoading] = useState(false); const router = useRouter(); useEffect(() => { const handleStart = () => setIsLoading(true); const handleComplete = () => setIsLoading(false); router.events.on('routeChangeStart', handleStart); router.events.on('routeChangeComplete', handleComplete); router.events.on('routeChangeError', handleComplete); return () => { router.events.off('routeChangeStart', handleStart); router.events.off('routeChangeComplete', handleComplete); router.events.off('routeChangeError', handleComplete); }; }, [router]); return ( <html lang="zh-CN"> <body> {isLoading && <Loading />} {children} </body> </html> ); }
这种方式脱离Next.js默认的loading.tsx路由规则,通过客户端路由事件手动控制全局加载状态,所有页面切换都会触发根loading.tsx。
2. 路由组+极简复用文件
创建一个全局加载组件,再在每个路由段的loading.tsx中导入复用(文件内容极简,无冗余逻辑):
// app/components/GlobalLoading.tsx export default function GlobalLoading() { // 根目录loading.tsx的原内容 return <div>全局加载中...</div>; }
然后在各路由段的loading.tsx中直接导入:
// app/child/loading.tsx import GlobalLoading from '../components/GlobalLoading'; export default GlobalLoading;
// app/child/grandchild/loading.tsx import GlobalLoading from '../../components/GlobalLoading'; export default GlobalLoading;
这种方式符合Next.js路由规则,同时避免重复编写加载逻辑,仅需每个路由段添加一个极简的loading.tsx文件。
注意事项
Next.js官方目前未提供让子路由段自动回退到父级loading.tsx的配置,上述两种方式是当前版本下的可行方案;若使用服务器组件导航(如Link组件默认行为),第一种方式的客户端路由事件依然会触发,因为路由变化会同步到客户端。
内容的提问来源于stack exchange,提问作者TJBlackman

