本篇選用 NProgress 來加入進度條的功能。
首先引入 NProgress:
npm install --save nprogress
npm install --save-dev @types/nprogress
因為專案使用的是 Next.js 的 App Router,在 App Router 中已經沒有 Pages Router 的那些 events 了,取而代之的是用 useEffect()
監聽 pathname
跟 searchParams
。
官方用例是這樣的:
'use client'
import { useEffect } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'
export function NavigationEvents() {
const pathname = usePathname()
const searchParams = useSearchParams()
useEffect(() => {
const url = `${pathname}?${searchParams}`
console.log(url)
// You can now use the current URL
// ...
}, [pathname, searchParams])
return null
}
那要跟 nprogress 合著使用我的用法是一樣建立一個 NProgressNavigationEvents.tsx
Component:
( 名字有點長,但是為了一眼看出功能,做了點取捨 )
// @/app/components/NProgressNavigationEvents.tsx
"use client";
import { useEffect, Suspense } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
NProgress.configure({ easing: "ease", speed: 500 });
function Search() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
NProgress.done();
}, [pathname, searchParams]);
return null;
}
// 這樣包裹是因為不這樣的話在 build 的時候會有 Missing Suspense boundary with useSearchParams 的錯誤。
export default function ProgressBar() {
return (
<Suspense>
<Search />
</Suspense>
);
}
在這個 Component 內不僅有監聽了 routerChangeComplete 事件,還載入了 css 樣式跟初始化了 NProgress。
有了這個 Component 之後在 layout.tsx
中引入套入到全域,這麼一來全站都會有 NProgress 的設定跟基於 router 事件的 done()
進度條完成事件,接下來要做的就是在需要的地方加入 NProgress 的 start()
進度條開始事件。
第一個要加入進度條行為的是從文章列表內點擊 READ MORE 的跳頁行為,非常簡單,只要在 <Link>
加入個 onClick={() => NProgress.start()}
事件,就可以輕鬆辦到了。
"use client";
// ...
import Link from "next/link";
import NProgress from "nprogress";
export default function PostPreview({ post }: { post: BlogPost }) {
return (
{/* ... */}
<Link
className="inline-block border-2 border-neutral-200 text-neutral-200 px-3 py-2 text-sm font-bold rounded uppercase"
href={`/${post.slug.current}`}
onClick={() => NProgress.start()} // <- 加入 start() 事件
>
Read More
</Link>
{/* ... */}
);
}
基本上所有 router 相關的要加入,只要重複上面的動作都可以順利加入。
現在如果不要做在 router 相關的事件上,如果要做在 Load More:載入更多文章的事件上呢?
那就更簡單了,因為 NProgress 剛才已經在 layout.tsx
內初始化過了,所以不用多做設定,直接引入 NProgress 對它進行操作就好了:
"use client";
// ...
import NProgress from "nprogress";
export default function PostsBlock() {
// ...
async function loadMore() {
NProgress.start(); // 開始進度條
const lastPost = R.last(posts);
await fetchPosts(lastPost?.publishedAt, lastPost?.title); // 注意要 await 確定事件結束
NProgress.done(); // 結束後再結束進度條
}
return (
{/* ... */}
<button onClick={loadMore}>Load More</button>
{/* ... */}
</div>
);
}
這樣就連點擊載入更多文章都會有進度條了。
( 不過這只是個示例,我預期只有換頁事件才要有進度條 )