为什么 NextJS 的 getStaticPaths 在我运行下一个构建时会抛出错误?

时间:2021-03-15 05:16:12

标签: javascript typescript next.js static-site

这里发生的事情是我想通过 getStaticPaths 结合 getStaticProps 来使用 Next.js 的 SSG。在开发中一切正常。但是当我运行构建命令时,它会抛出这样的错误:

<块引用>

在 /mentor/[id] 的 getStaticPaths 中没有以字符串形式提供必需的参数 (id)

我的文件夹结构如下:

|- pages
   |- api
      |- mentors
         |- [id].ts
         |- index.ts
   |- mentor
      |- [id].tsx
   |- _app.tsx
   |- _document.tsx
   |- index.tsx

我的导师 API 如下所示:

pages/api/mentors/index.ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export default (req: NextApiRequest, res: NextApiResponse) => {
  res.status(200).json(mentors);
};

我的导师/:id API 看起来像这样:

pages/api/mentors/[id].ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export default (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query;
  const selectedMentor = mentors.find((mentor) => mentor.id.toString() === id);
  res.status(200).json(selectedMentor);
};

dummyDatas 看起来像这样:

utils/dummyDatas.ts

export const mentors: MentorType[] = [
  {
    id: 1,
    name: "John Doe",
    description:
      "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Rerum quidem earum perferendis, facilis quos vero, nobis maxime explicabo quo adipisci modi a ducimus? Dicta labore delectus consequatur sint, nisi temporibus.",
    image:
      "https://images.unsplash.com/photo-1539571696357-5a69c17a67c6?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=634&q=80",
  },
  ...
]

现在有了所有这些资源,我想尝试 SSG,这是我实现 SSG 的代码。

pages/mentor/[id].tsx

import axios from "axios";
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next";

// Components
import { MentorDetail } from "containers";
import { MentorType } from "utils/types";
import { Header } from "molecules";

interface IProps {
  mentor: MentorType;
}

function Detail({ mentor }: IProps) {
  return (
    <>
      <Header loggedIn={false} />
      <MentorDetail mentor={mentor} />
    </>
  );
}

export const getStaticPaths: GetStaticPaths = async () => {
  try {
    const { data } = await axios.get("http://localhost:3000/api/mentors");
    const paths = data.map((mentor: MentorType) => {
      return {
        params: { id: mentor.id.toString() },
      };
    });
    return {
      paths,
      fallback: false,
    };
  } catch {
    return { paths: [{}], fallback: false };
  }
};

export const getStaticProps: GetStaticProps = async (
  context: GetStaticPropsContext
) => {
  try {
    const { data } = await axios.get(
      `http://localhost:3000/api/mentors/${context.params.id}`
    );
    return {
      props: {
        mentor: data,
      },
    };
  } catch {
    return {
      props: {},
    };
  }
};

export default Detail;

1 个答案:

答案 0 :(得分:0)

这个问题很可能是因为在构建时您的请求失败了,因此 catch 块返回一个空的 paths 数组。

您不应使用 axiosgetStaticProps/getStaticPaths 中调用内部 API 路由。来自 Next.js 文档:

<块引用>

您不应使用 fetch()(或在本例中为 axios)来调用 getStaticProps 中的 API 路由。相反,直接导入 API 路由中使用的逻辑。您可能需要为这种方法稍微重构您的代码。

从外部 API 获取没问题!

您需要稍微重构 API 路由代码以导出其逻辑。

// pages/api/mentors/[id].ts

import { mentors } from "utils/dummyDatas";
import { NextApiRequest, NextApiResponse } from "next";

export const getMentorById = (id: string) => mentors.find((mentor) => mentor.id.toString() === id);

export default (req: NextApiRequest, res: NextApiResponse) => {
  const { id } = req.query;
  const selectedMentor = getMentorById(id);
  res.status(200).json(selectedMentor);
};

然后在您的 getStaticPaths 中,您需要直接导入 mentors 数据。

// pages/mentor/[id].tsx

import { mentors } from "<path-to>/utils/dummyDatas"; // Replace with your actual path to the file

export const getStaticPaths: GetStaticPaths = async () => {
    const paths = mentors.map((mentor: MentorType) => {
        return {
            params: { id: mentor.id.toString() }
        };
    };

    return {
        paths,
        fallback: false
    };
};

在您的 getStaticProps 中,您需要重用 API 路由中定义的 getMentorById 函数,而不是发出请求。

// pages/mentor/[id].tsx

import { getMentorById } from "<path-to>/api/mentors/[id]" // Replace with your actual path to the file

export const getStaticProps: GetStaticProps = async (context: GetStaticPropsContext) => {
    const data = getMentorById(context.params.id);

    return {
        props: {
            mentor: data
        }
    };
};