首页 > 解决方案 > 使用 NextJS 和 Material UI React 从 API 获取数据

问题描述

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

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

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

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

这是我的代码。我试图保持干净和简单。

书页(在“页面”目录中)

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;

标签: reactjsmaterial-uinext.js

解决方案


getStaticProps如果您想使用诸如or之类的数据获取方法,您应该在此处使用动态路由getServerSideProps

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

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

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;

使用 static-site-generation 因为页面是动态的,你必须提供一个路径列表,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;

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

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


推荐阅读