iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
佛心分享-SideProject30

用 Sanity 跟 Nextjs 重寫個人部落格系列 第 24

Day 24 - Next.js App Router 使用 NProgress 加入進度條

  • 分享至 

  • xImage
  •  

本篇選用 NProgress 來加入進度條的功能。

首先引入 NProgress:

npm install --save nprogress

npm install --save-dev @types/nprogress

因為專案使用的是 Next.js 的 App Router,在 App Router 中已經沒有 Pages Router 的那些 events 了,取而代之的是用 useEffect() 監聽 pathnamesearchParams

官方用例是這樣的:

'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() 進度條完成事件,接下來要做的就是在需要的地方加入 NProgressstart() 進度條開始事件。

第一個要加入進度條行為的是從文章列表內點擊 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>
  );
}

這樣就連點擊載入更多文章都會有進度條了。
( 不過這只是個示例,我預期只有換頁事件才要有進度條 )


上一篇
Day 23 - Next.js 使用 Sanity 網站設定
下一篇
Day 25 - Sanity Webhook 創立與 Header 解析
系列文
用 Sanity 跟 Nextjs 重寫個人部落格30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言