在Next.js中使用路由器的动态内容

82 阅读3分钟

Next.js中使用Link链接两个页面的文章中,我们看到了如何将主页链接到博客页面。

博客是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 参数内。

好吧,这一下子有点多了。

路由器是什么?

路由器是Next.js提供的一个库。

我们从next/router 中导入它。

import { useRouter } from "next/router";

而一旦我们有了useRouter ,我们就使用实例化的路由器对象。

const router = useRouter();

一旦我们有了这个路由器对象,我们就可以从中提取信息。

特别是我们可以通过访问router.query.id ,获得[id].js 文件中URL的动态部分。

因此,让我们继续在实践中应用所有这些东西。

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

import { useRouter } from "next/router";

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

  return (
    <>
      <h1>Blog post</h1>
      <p>Post id: {router.query.id}</p>
    </>
  );
};

现在,如果你进入http://localhost:3000/blog/test 路由器,你应该看到这个。

我们可以使用这个id 参数,从一个帖子的列表中收集帖子。例如,从一个数据库中。为了保持简单,我们将在项目根文件夹中添加一个posts.json 文件。

{
  "test": {
    "title": "test post",
    "content": "Hey some post content"
  },
  "second": {
    "title": "second post",
    "content": "Hey this is the second post content"
  }
}

现在我们可以导入它并从id 关键中查找帖子。

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> 检查。

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 中列出这些帖子来完成这个博客例子。

import posts from "../posts.json";

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

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

export default Blog;

我们可以通过从next/link 中导入Link ,并在帖子循环中使用它,将它们链接到各个帖子页面。

import Link from "next/link";
import posts from "../posts.json";

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

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

export default Blog;