/

在 Next.js 中使用路由器設置動態內容

在 Next.js 中使用路由器設置動態內容

如何在 Next.js 網站中設置動態內容?

使用 Link 在 Next.js 中連接兩個頁面文章中,我們看到了如何將主頁連接到博客頁面。

博客是 Next.js 的一個很好的用例,我們將在本章中繼續探索,並添加博客文章

博客文章有動態的 URL,例如標題為“Hello World”的文章可能具有 URL /blog/hello-world,標題為“我的第二篇文章”的文章可能具有 URL /blog/my-second-post

這些內容是動態的,可能來自數據庫、markdown 文件或其他來源。

Next.js 可以根據動態 URL 提供動態內容。

我們可以通過使用 [] 語法創建動態 URL。

如何做到這一點呢?我們添加一個 pages/blog/[id].js 文件。此文件將處理所有 /blog/ 路由下的動態 URL,例如上面提到的 /blog/hello-world/blog/my-second-post 等。

在文件名中,方括號中的[id]表示任何動態的內容將放在路由器的查詢屬性的id參數中。

好的,一次介紹了這麼多東西。

什麼是路由器(router)

路由器是 Next.js 提供的一個庫。

我們從 next/router 導入它:

1
import { useRouter } from "next/router";

一旦我們有了 useRouter,我們可以使用以下代碼來實例化路由器對象:

1
const router = useRouter();

一旦我們有了這個路由器對象,我們可以從中提取信息。

特別是我們可以通過訪問 [id].js 文件中的 router.query.id 來獲取 URL 的動態部分。

讓我們繼續實踐這些事情。

創建文件 pages/blog/[id].js

1
2
3
4
5
6
7
8
9
10
11
12
import { useRouter } from "next/router";

export default () => {
const router = useRouter();

return (
<>
<h1>博客文章</h1>
<p>文章 ID: {router.query.id}</p>
</>
);
};

現在,如果您轉到 http://localhost:3000/blog/test ,您應該會看到以下內容:

我們可以使用此 id 參數從一個文章列表中獲取文章。例如,可以從數據庫獲取文章。為了保持簡單,我們將在項目根目錄中添加一個 posts.json 文件:

1
2
3
4
5
6
7
8
9
10
{
"test": {
"title": "測試文章",
"content": "嘿,這是一些文章內容"
},
"second": {
"title": "第二篇文章",
"content": "嘿,這是第二篇文章的內容"
}
}

現在,我們可以導入它並根據 id 鍵查找文章:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useRouter } from "next/router";
import posts from "../../posts.json";

export default () => {
const router = useRouter();
const post = posts[router.query.id];

return (
<>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
);
};

重新載入頁面應該顯示正確的結果:

但並沒有!相反,我們在控制檯上和瀏覽器中都收到了一個錯誤:

為什麼?因為..在渲染過程中,當組件被初始化時,數據還沒有準備好。我們將在下一節中看到如何使用 getInitialProps 將數據提供給組件。

現在,在返回 JSX 之前,添加一個小小的 if (!post) return <p></p> 檢查:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useRouter } from "next/router";
import posts from "../../posts.json";

export default () => {
const router = useRouter();
const post = posts[router.query.id];

if (!post) return <p></p>;

return (
<>
<h1>{post.title}</h1>
<p>{post.content}</p>
</>
);
};

現在應該可以正常工作了。最初,該組件在沒有動態的 router.query.id 信息的情況下被渲染。渲染完成後,Next.js 會根據查詢的值觸發更新,並且頁面會顯示正確的信息。

並且,如果您檢視源代碼,HTML 中會有一個空的 <p> 標記:

我們很快將解決這個問題,該問題導致無法實現服務器端渲染(SSR),這對於我們的用戶來說,加載時間、SEO 和社交分享都是有害的,正如我們之前討論的那樣。

我們可以通過在 pages/blog.js 中列出那些文章來完善博客示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import posts from "../posts.json";

const Blog = () => (
<div>
<h1>博客</h1>

<ul>
{Object.entries(posts).map((value, index) => (
<li key={index}>{value[1].title}</li>
))}
</ul>
</div>
);

export default Blog;

我們可以通過導入 next/link 並在文章循環中使用它將它們鏈接到個別的博客文章頁面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Link from "next/link";
import posts from "../posts.json";

const Blog = () => (
<div>
<h1>博客</h1>

<ul>
{Object.entries(posts).map((value, index) => (
<li key={index}>
<Link href="/blog/[id]" as={`/blog/${value[0]}`}>
<a>{value[1].title}</a>
</Link>
</li>
))}
</ul>
</div>
);

export default Blog;

tags: [“Next.js”, “路由器 (router)”, “動態內容 (dynamic content)”, “數據庫 (database)”, “markdown 文件”]