首页 > 解决方案 > 如何基于 GraphQL API 的 slug 使用 Next.js 进行动态路由?

问题描述

我很难理解基于变量的动态路由。我可以使用 Next.js 获取具有动态路由的单个页面的集合中的项目列表,但不能获取单个项目及其字段。

背景

我有一个带有 GraphQL API 的 KeystoneJS 无头 CMS。我正在尝试创建一个包含帖子列表和单个帖子页面的简单博客。我已经能够查询并返回一个帖子列表,但我需要根据 slug 字段获取一个单独的帖子,以便可以在/posts/[slug].js.

我试过的

我一直在使用 Apollo Client 来处理查询。我有一个apolloClient.js连接到 API 的文件:

// apolloClient.js
import { ApolloClient, InMemoryCache } from "@apollo/client";

export default new ApolloClient({
  uri: "http://localhost:3000/admin/api",
  cache: new InMemoryCache(),
});

我有一个post.service.js文件来查询 API:

// post.service.js
import { gql } from "@apollo/client";
import apolloClient from "../_utils/apolloClient";

export async function getAll() {
  return apolloClient
    .query({
      query: gql`
        query {
          allPosts {
            id
            term
            slug
          }
        }
      `,
    })
    .then((result) => result.data.allPosts);
}

export async function getBySlug(slug) {
  return apolloClient
    .query({
      query: gql`
        query {
          Post(slug: $slug) {
            id
            title
            lead
            body
          }
        }
      `,
    })
    .then((result) => {
      return result.data.Post;
    });
}

最后,posts/[slug].js我试图像这样返回数据:

//[slug].js
import Head from "next/head";
import { ApolloClient, InMemoryCache, gql } from "@apollo/client";
import { getAll, getBySlug } from "../../_services/post.service";

export default function Post({ post }) {
  return (
    <div>
      <Head>
        <title>Launchpad</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <h1>{post.term}</h1>
      </main>
      <footer>
        <p>{post.lead}</p>
      </footer>
    </div>
  );
}

export async function getStaticPaths() {
  const posts = await getAll();

  const paths = posts.map((post) => ({
    params: { id: post.slug },
  }));

  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const post = await getBySlug(params.id);

  return { props: { post } };
}

显然,这是行不通的。我不能将变量(我假设它是 slug)正确地传递到查询中,并且阅读了几个教程后,我仍然无法理解它。有谁看到我做错了什么?

标签: reactjsgraphqlnext.jsapolloapollo-client

解决方案


在对象getStaticPaths中返回的键params需要匹配动态路由命名。在您的情况下,由于您使用posts/[slug].js的是路线,因此您需要params使用 format { slug: post.slug }

export async function getStaticPaths() {
  const posts = await getAll();

  const paths = posts.map((post) => ({
    params: { slug: post.slug }, // Rename to `slug`
  }));

  return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
  const post = await getBySlug(params.slug); // Rename to `params.slug`

  return { props: { post } };
}

编辑:关于请求问题,以下更改getBySlug应使其按预期工作。

export async function getBySlug(slug) {
  return apolloClient
    .query({
      query: gql`
        query Post($slug: String){
          post(slug: $slug) {
            id
            title
            lead
            body
          }
        }
      `,
      variables: {
        slug
      }
    })
    .then((result) => {
      return result.data.Post;
    });
}

推荐阅读