
Next.js 13+ App Router 移除了 Router.events,但可通过 useTransition + 自定义 Link 组合实现等效的导航加载状态监听,并配合 NProgress 等库构建平滑进度条体验。
next.js 13+ app router 移除了 `router.events`,但可通过 `usetransition` + 自定义 link 组合实现等效的导航加载状态监听,并配合 nprogress 等库构建平滑进度条体验。
在 App Router 中,next/router 的 Router.events(如 'routeChangeStart'、'routeChangeComplete')暂未提供直接等价 API —— 这是当前官方明确的设计取舍。React Server Components 的流式渲染与客户端导航模型已深度集成 React 的并发特性,因此推荐使用原生 useTransition 配合 useRouter 实现精准、可预测的过渡状态控制。
✅ 推荐方案:useTransition + 自定义 <link>(官方推荐)
核心思路:将所有导航包裹在 startTransition 中,利用 isPending 标志实时响应导航中状态:
// app/components/ProgressLink.tsx
'use client';
import { useTransition } from 'react';
import { useRouter } from 'next/navigation';
import NextLink, { LinkProps } from 'next/link';
import NProgress from 'nprogress'; // npm install nprogress
// 可选:全局配置 NProgress(建议在 _app.tsx 或 layout.tsx 中初始化)
NProgress.configure({
showSpinner: false,
minimum: 0.3,
easing: 'ease',
speed: 200,
});
export function ProgressLink({
href,
children,
replace = false,
...props
}: Omit<linkprops> & { href: string; replace?: boolean }) {
const router = useRouter();
const [isPending, startTransition] = useTransition();
// 导航开始时触发进度条
if (isPending) {
NProgress.start();
}
// 导航完成或失败时结束(注意:useTransition 不区分成功/失败,需结合副作用)
if (!isPending && typeof window !== 'undefined' && NProgress.isStarted()) {
NProgress.done();
}
return (
<nextlink href="%7Bhref%7D" onclick="{(e)"> {
e.preventDefault();
startTransition(() => {
const url = href.toString();
if (replace) {
router.replace(url);
} else {
router.push(url);
}
});
}}
{...props}
>
{children}
</nextlink>
);
}</linkprops>
⚠️ 注意事项:
dmap-jsapi-skill下载DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
useTransition的isPending仅反映过渡是否进行中,不区分成功/失败;若需错误处理(如跳转 404),应配合useEffect监听router状态变化或使用error.tsx边界捕获。NProgress.done()在isPending === false时调用,但为避免重复触发,建议添加NProgress.isStarted()判断。- 所有含状态逻辑的组件必须标记
'use client',且不能出现在服务端组件树中。
? 替代方案(按推荐度排序)
| 方案 | 说明 | 适用场景 |
|---|---|---|
nextjs-progressloader |
轻量封装,自动注入 <progressbar></progressbar> 并监听 useRouter().push/replace
|
快速落地,无需自定义 Link |
react-transition-progress |
Vercel 官方维护的实验性库,基于 useTransition + useEffect 封装进度逻辑 |
追求与 Next.js 内部机制高度对齐 |
全局 loading.tsx + Suspense
|
利用 App Router 原生 loading.tsx 文件 + Suspense 边界展示骨架屏 |
适合页面级加载,无法实现细粒度进度条 |
? 总结
- ❌ 不要尝试模拟
Router.events—— App Router 没有事件总线,强行 polyfill 易导致状态不一致; - ✅ 优先采用
useTransition+ 自定义导航组件,这是 React 并发模型下的标准实践; - ✅ 将
NProgress初始化放在客户端入口(如layout.tsx),确保单例行为; - ✅ 生产环境建议搭配
nprogress.css并微调样式,提升 UX 一致性。
通过该方案,你不仅能复现 Pages Router 的进度条效果,更能获得更稳定、可中断、与 React 渲染周期深度协同的现代导航体验。











