在 NextJS 中使用“getStaticPaths”和“getStaticProps”创建动态路由

Posted

技术标签:

【中文标题】在 NextJS 中使用“getStaticPaths”和“getStaticProps”创建动态路由【英文标题】:Creating Dynamic Routes using 'getStaticPaths' and 'getStaticProps' in NextJS 【发布时间】:2020-10-18 17:56:44 【问题描述】:

我正在尝试根据每本书的 "id" 查询字符串创建动态页面,以在单独的页面上显示单个书籍的详细信息(即标题/作者)。在previous question 我问过,用户的回答非常有帮助,我对如何正确使用getStaticPathsgetStaticProps 有了更好的理解。但是,我的代码中并没有详细说明如何执行此操作。

这是基本设置和上下文。

    我正在运行 NextJS 9.4,并希望使用 API 端点而不是直接查询数据库。 图书数据从 MongoDB Atlas 数据库中提取并使用 Mongoose MongoDB 中的文档具有 "_id" 作为唯一 ID。 我已尝试合并现有的 Github 示例和 NextJS 文档并从中学习,但我仍然收到以下错误。

Error: A required parameter (id) was not provided as a string in getStaticPaths for /book/[id]

这是我到目前为止的代码。我现在尽量保持代码干净。

export default function Book( book ) 
    return (
        <article>
            <h1>Book Details Page</h1>
            <p>book.title</p>
            <p>book.author</p>
        </article>
    )


export async function getStaticPaths() 
    
    const url = `$baseUrl/api/books/books`

    const response = await axios.get(url);

    const books = response.data

    const paths = books.map((book) => (
        params:  id: book.id ,
    ))
    
    return  paths, fallback: false 


export async function getStaticProps( params ) 
    const url = `$baseUrl/api/books/books/$params.id`
    const res = await axios.get(url)
    const book = await res.json()

    return  props:  book 

API 端点如下所示:

import Book from '../../../models/Book';
import dbConnect from '../../../utils/dbConnect';

// conects to the database
dbConnect();

// This gets all the book from the database
export default async (req, res) => 
    const books = await Book.find()
    res.status(200).json(books)

我们将不胜感激任何支持或反馈。一旦我完成这项工作,我希望能够理解并帮助其他人使用 NextJs 创建动态路由。谢谢。

【问题讨论】:

这是函数getStaticPaths 中的拼写错误“$baseUrl/api/books/books”还是正确的端点?从错误看来,路由参数id 设置不正确。您可以在控制台中记录books 的值并验证您获取的数据是否正确吗? 正如您所说,Mongo 文档包含一个_id 字段,但是当您映射books 响应时,您使用的是books.id。那可能是你的问题。请改用books._id。此外,始终信守诺言。由于您使用的是 async/await,因此请使用 try/catch 块。 【参考方案1】:

您不能在 getStaticPropsgetStaticPaths 内调用 Next.js API 路由。这些函数在构建时执行,因此没有服务器正在运行来处理请求。您需要直接向 DB 提出请求。

如果你想保持干净,你可以创建一个像 allBooksIds() 这样的帮助模块,并将数据库查询保存在一个单独的文件中。

查看相同的问题 - API call in NextJS getStaticProps

【讨论】:

感谢 Nikolai 提供的信息!我现在明白我不应该从 getStaticProps 获取 API 路由,而是学习如何直接在 getStaticProps 中编写服务器端代码。我发现 NextJS Github 有很好的 mongo-mongoose 示例。感谢您的帮助。 @Nikolai:我遇到了类似的问题并得到了您的回答。我不知道,如果我理解错误,但在 Next.js 文档中有一些示例,其中 API 调用是在 getStaticPaths (nextjs.org/docs/basic-features/…) 中进行的。你能告诉我区别在哪里吗? 好的,我认为不同之处在于,在示例中他们进行了外部 api 调用。但是,也许你可以添加一个小例子来解决这个问题?会很有帮助的! @NikolaiKiselev 请看这个线程。我在这里遇到了一些奇怪的问题***.com/questions/67624322/…【参考方案2】:

只需在 getStaticPaths 中添加 toString() 方法,因为书籍 ID 的类型为 ObjectID("ID"),如果您执行 params: id: book._id.toString() ,它会将 ObjectID("ID") 转换为 getStaticPaths() 接受的字符串类型。 nextjs 部分的完整代码如下,还更新了您的 API 路由,如下所示:-

上面是API路由,下面是Nextjs Page

import Book from '../../../models/Book';
import dbConnect from '../../../utils/dbConnect';

// conects to the database
dbConnect();

// This gets all the book from the database
export default async (req, res) => 
    const books = await Book.find()
    res.status(200).json(books)


export default function Book( book ) 
    return (
        <article>
            <h1>Book Details Page</h1>
            <p>book.title</p>
            <p>book.author</p>
        </article>
    )


export async function getStaticPaths() 
    
    const url = `$baseUrl/api/books/books`

    const response = await axios.get(url);

    const books = response.data

    const paths = books.map((book) => (
        params:  id: book._id.toString() ,
    ))
    
    return  paths, fallback: false 


export async function getStaticProps( params ) 
    const url = `$baseUrl/api/books/books/$params.id`
    const res = await axios.get(url)
    const book = await res.json()

    return  props:  book 

希望对你有帮助

【讨论】:

以上是关于在 NextJS 中使用“getStaticPaths”和“getStaticProps”创建动态路由的主要内容,如果未能解决你的问题,请参考以下文章

NextJS - 无法在 Tailwind CSS 中使用自定义颜色

如何在客户端 NextJS 中使用 Apollo GraphQL 订阅?

如何在 Storybook 中使用 NextJS 的 'useRouter()' 钩子

让 styled-jsx 在 NextJS 中使用 tailwindcss [关闭]

如何在 nextJS 中使用 <Head>

图像不会出现在 Nextjs 和 Strapi 项目中