【问题标题】:Fetching Data from API using NextJS and Material UI React使用 NextJS 和 Material UI React 从 API 获取数据
【发布时间】:2020-10-08 14:59:45
【问题描述】:

我正在尝试根据每本书的 “id” 的查询字符串创建动态页面,在单独的页面上显示单个书籍的详细信息(即标题/作者等)。但是,我很难理解如何使用 NextJS 向 API 端点发出请求,该端点将根据其 "id" 获取图书详细信息。我想使用 Material UI 作为 UI 框架。

问题:当我运行 npm run dev 时,图书页面会加载,但图书的“道具”并未传递给 BookAttributes 组件。我在书页中添加的console.log(book)undefinedBookAttributes 中的console.log(title) 也是未定义的。

  1. 我已经在 POSTMAN 中测试了 API 端点,它似乎可以工作。
  2. 当我使用 Semantic UI-React 而不是 Material UI 重构相同的代码时,书页可以正确加载。
  3. 我使用 Material UI 网站上的 NextJS Material UI 起始模板作为基线。

我对 NextJS 和 Material UI 还很陌生,因此非常感谢您的帮助和指导。感谢您对此的帮助!

这是我的代码。我尽量保持简洁。

BOOK PAGE(在“pages”目录中)

import axios from 'axios';
import BookAttributes from '../components/Book/BookAttributes';

function Book({ book }) {

    console.log(book)

    return (
        <>
            <h1>Book Page</h1>
            <BookAttributes {...book} />
        </>
    )
}

Book.getInitalProps = async ({ query: { _id } }) => {
    const url = 'http://localhost:3000/api/book';
    const payload = { params: { _id }}
    const response = await axios.get(url, payload)
    return { book: response.data }
}

export default Book;

BOOK API ENDPOINT(在“pages/api”目录中)

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

connectDb()

export default async (req, res) => {
    const { _id } = req.query
    const book = await Book.findOne({ _id })
    res.status(200).json(book);
}

BOOK ATTRIBUTE COMPONENT(在“组件”目录中)

import React from 'react';

function BookAttributes({ title }) {

    console.log(title)

    return (
        <>
            <h1>{title}</h1>
        </>
    )
}

export default BookAttributes;

【问题讨论】:

  • 你用的是哪个版本的nextjs?如果您使用的是 next 9.3 或更高版本,我建议使用getServerSidePropsgetStaticProps 来获取数据,而不是getInitialProps
  • 感谢您的帮助。是的,我正在运行 NextJS 9.3。由于我对 NextJS 很陌生,您能否提供一个示例,说明如何在上面的代码中使用“getServerSideProps”和“getStaticProps”?我尝试使用 NextJS 网站上的示例,但无法使其正常工作。非常感谢。
  • 您是在http://localhost:3000/book?id=something 还是http://localhost:3000/book?_id=something 上进行测试?
  • @GregoryWiley 是的,但首先您需要了解dynamic routing 的工作原理以及何时使用getStaticPropsgetServerSideProps。这就是为什么我建议您阅读 nextjs docs 中的基础知识并查看 dynamic routes 部分。
  • @subashMahapatra 好点。我同意。我现在正在学习 NextJS 教程,并将专注于动态路由部分。如果您有任何其他代码示例,请告诉我。谢谢。

标签: reactjs material-ui next.js


【解决方案1】:

如果您想使用getStaticPropsgetServerSideProps 等数据获取方法,您应该在此处使用动态路由。

您可以创建一个类似pages/book/[id].js 的页面。但是要生成页面,您必须决定要运行哪种数据获取方法。如果页面的数据不经常更改,您可以选择使用 getStaticProps 的静态站点生成,这将在构建时生成页面。如果数据将发生很大变化,您可以使用getServerSideProps 进行服务器端渲染或获取数据客户端。

这里是您的用例示例,您可以使用 getServerSideProps 进行服务器端渲染,请记住,getServerSideProps 中的 API 调用可能会失败,因此您应该进行适当的错误处理。

pages/book/[id].js

import axios from 'axios';
import BookAttributes from '../components/Book/BookAttributes';

export const getServerSideProps = async (ctx) => {
   const bookId = ctx.params?.id
   const url = 'http://localhost:3000/api/book';
   const response = await axios.get(url, { params: { _id: bookId} })

   return {
      props: {
        book: response.data
      }
   }

}

function Book({ book }) {
   return (
      <>
        <h1>Book Page</h1>
        <BookAttributes {...book} />
     </>
    )
}

export default Book;

使用静态站点生成 因为页面是动态的,所以您必须提供 nextjs 将为其生成页面的路径列表。您可以通过导出一个名为 getStaticPaths 的异步函数来做到这一点。

pages/book/[id].js

import axios from 'axios';
import BookAttributes from '../components/Book/BookAttributes';

export const getStaticPaths = async () => {
  // here you have two options if you know all the ids of the books
  // you can fetch that data from the api and use all the ids to generate
  // a list of paths or show a fallback version of page if you don't know all
  // ids and still want the page to be static
  // Pseudo code might look like this
  const res = await axios.get('api-endpoint-to-fetch-all-the-books')

  const paths = res.data.map(book => ({ params: { id: book.id }}))

  return {
     paths,
     fallback: false
  }
}

export const getStaticProps = async (ctx) => {
   const bookId = ctx.params?.id
   const url = 'http://localhost:3000/api/book';
   const response = await axios.get(url, { params: { _id: bookId} })

   return {
      props: {
        book: response.data
      }
   }

}

function Book({ book }) {
   return (
      <>
        <h1>Book Page</h1>
        <BookAttributes {...book} />
     </>
    )
}

export default Book;

getStaticPaths 的返回值中的fallback 属性有点重要,需要理解。如果您知道页面所需的所有id,则可以将fallback 设置为false。在这种情况下,nextjs 将简单地为函数getStaticPaths 未返回的所有路径显示一个404 错误页面。

如果fallback 设置为true,nextjs 将显示回退版本的页面,而不是404 页面,用于未从getStaticPaths 函数返回的路径。现在应该在哪里将fallback 设置为true?假设在您的情况下,经常将新书籍添加到数据库中,但书籍的数据不会经常更改,因此您希望页面是静态的。在这种情况下,您可以将 fallback 设置为 true 并根据可用的书籍 ID 生成路径列表。对于新书,nextjs 将首先显示页面的后备版本,然后根据请求中提供的 id 获取数据,并将数据作为 JSON 发送,用于在客户端呈现页面。

【讨论】:

  • 早上好@subashMahaptra 非常感谢您的详细回答和整体帮助。我将逐行研究您的示例以更好地理解。您的示例和 NextJS 的教程帮助我成为了一名更好的 JavaScript 开发人员。
  • @GregoryWiley 这是由 nextjs 在 repo 中提供的examples 列表。当您尝试在应用中实现需要一些额外设置的其他库时,这些示例也会有所帮助。
猜你喜欢
  • 2018-01-31
  • 2021-04-09
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 2018-10-19
  • 2021-09-26
  • 1970-01-01
  • 2020-07-07
相关资源
最近更新 更多