reactjs - 如何基于 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)正确地传递到查询中,并且阅读了几个教程后,我仍然无法理解它。有谁看到我做错了什么?
解决方案
在对象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;
});
}
推荐阅读
- visual-studio-code - 如何使用预先选择的文件在 vscode 中打开文件夹选择器对话框?
- vue.js - 两个不同的相同 v-for 循环
- r - 使用 knitr 从 rmarkdown 生成 .md 文档。有没有办法获得 atx 样式的标题而不是 Settext 样式的标题?
- jquery - 使用 Cheerio/jQuery 时,如何从所有具有相同名称的类中获取文本?
- python-3.x - pd.Series 的串联导致 pandas.core.indexes.base.InvalidIndexError
- php - 如何删除身份验证令牌“角色”以实现 MFA 系统?
- angular - serviceFactory 作为提供者对象中的依赖项(deps:[]) - 有可能吗?
- javascript - javascript中的乘法表应该显示一个从10到19开始的表
- eclipse - 如何在 Xtext generator.xtend 中读取 XML 文件
- c++ - 我如何使用 for 循环来比较不同大小的数组