我想使用Notion API在基于Next.js的个人网站上创建一个博客网站。我必须说,我是Next.js和Notion API的新手。我拉帖子没有问题,但我想把端点中的id搞得一团糟,用帖子标题代替它们。在尝试这样做的时候——通过查看一些资源——当我试图访问以下状态的帖子时,我得到了一个404错误。在捕获这些文章的同时,我如何贿赂端点?
notion.js
import { Client } from "@notionhq/client";
const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
export const getDatabase = async (databaseId) => {
const response = await notion.databases.query({
database_id: databaseId,
});
return response.results;
};
export const getPage = async (id) => {
const response = await notion.pages.retrieve({ page_id: id });
return response;
};
export const getBlocks = async (blockId) => {
const response = await notion.blocks.children.list({
block_id: blockId,
page_size: 50,
});
return response.results;
};
[slug.js]
import Head from "next/head";
import Image from "next/image";
import { Fragment } from "react";
import { getDatabase, getPage, getBlocks } from "../../src/lib/notion";
import { databaseId } from "./index.js";
import { Text } from "../../src/components/text";
import Layout, { siteTitle } from "../../src/components/layout";
import { Client } from "@notionhq/client";
const renderBlock = (block) => {
const { type, id } = block;
const value = block[type];
switch (type) {
case "paragraph":
return (
<p>
<Text text={value.text} />
</p>
);
case "heading_1":
return (
<h1>
<Text text={value.text} />
</h1>
);
case "heading_2":
return (
<h2>
<Text text={value.text} />
</h2>
);
case "heading_3":
return (
<h3>
<Text text={value.text} />
</h3>
);
case "bulleted_list_item":
case "numbered_list_item":
return (
<li>
<Text text={value.text} />
</li>
);
case "to_do":
return (
<div>
<label htmlFor={id}>
<input type="checkbox" id={id} defaultChecked={value.checked} />{" "}
<Text text={value.text} />
</label>
</div>
);
case "toggle":
return (
<details>
<summary>
<Text text={value.text} />
</summary>
{value.children?.map((block) => (
<Fragment key={block.id}>{renderBlock(block)}</Fragment>
))}
</details>
);
case "child_page":
return <p>{value.title}</p>;
case "image":
const src =
value.type === "external" ? value.external.url : value.file.url;
const caption = value.caption ? value.caption[0].plain_text : "";
return (
<figure>
<Image src={src} alt={caption} />
{caption && <figcaption>{caption}</figcaption>}
</figure>
);
default:
return `❌ Unsupported block (${
type === "unsupported" ? "unsupported by Notion API" : type
})`;
}
};
export default function Post({ page, blocks }) {
if (!page || !blocks) {
return <div />;
}
return (
<Layout>
<Head>
<title>{siteTitle}</title>
</Head>
<article
className="prose dark:prose-invert dark:text-neutral-300"
style={{ marginTop: -80 }}
>
<h1 className="text-4xl font-bold tracking-tighter text-stone-900 dark:text-neutral-300">
<Text text={page.properties.Name.title} />
</h1>
<section>
{blocks.map((block) => (
<Fragment key={block.id}>{renderBlock(block)}</Fragment>
))}
</section>
</article>
</Layout>
);
}
export const getStaticPaths = async () => {
const notion = new Client({
auth: process.env.NOTION_TOKEN,
});
const data = await notion.blocks.children.list({
block_id: process.env.NOTION_TABLE_ID,
});
const paths = [];
data.results.forEach((result) => {
paths.push({
params: {
slug: slugify(result.properties.endpoint.rich_text[0].plain_text),
},
});
});
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
const { slug } = context.params;
const page = await getPage(slug);
const blocks = await getBlocks(page.id);
const childBlocks = await Promise.all(
blocks
.filter((block) => block.has_children)
.map(async (block) => {
return {
id: block.id,
children: await getBlocks(block.id),
};
})
);
const blocksWithChildren = blocks.map((block) => {
if (block.has_children && !block[block.type].children) {
block[block.type]["children"] = childBlocks.find(
(x) => x.id === block.id
)?.children;
}
return block;
});
return {
props: {
page,
blocks: blocksWithChildren,
},
revalidate: 1,
};
};
index.js
import Head from "next/head";
import Link from "next/link";
import Layout, { siteTitle } from "../../src/components/layout";
import { Client } from "@notionhq/client";
import { useEffect } from "react";
import { getDatabase } from "../../src/lib/notion";
import { Text } from "../../src/components/text";
import slugify from "slugify";
export const databaseId = process.env.NOTION_TABLE_ID;
export default function Blog({ posts }) {
useEffect(() => {
console.log(posts);
posts.map((post) => {
console.log(post);
});
});
return (
<Layout>
<Head>
<title>{siteTitle}</title>
</Head>
<section style={{ marginTop: -110 }}>
<div className="text-stone-900 prose lg:prose-xl dark:text-neutral-400">
<h3 className="text-3xl font-bold tracking-tighter text-stone-900 dark:text-neutral-300">
Blog
</h3>
</div>
<ol>
{posts.map((post) => (
<li
className="mt-7 text-stone-900 dark:text-neutral-400"
key={post.properties.endpoint.rich_text[0].plain_text}
>
<Link
href={`/blog/${slugify(
post.properties.endpoint.rich_text[0].plain_text
)}`}
>
<a className="text-2xl font-bold">
<Text text={post.properties.Name.title} />
<p className="text-lg font-thin">
{post.properties.description?.rich_text[0]?.plain_text}
</p>
</a>
</Link>
</li>
))}
</ol>
</section>
</Layout>
);
}
export async function getStaticProps() {
const database = await getDatabase(databaseId);
return {
props: {
posts: database,
},
revalidate: 1,
};
}
在[slug].js中,您使用的是const page = await getPage(slug);
,而getPage((函数只能接收id
变量。
我是NextJS的新手,但这是我的解决方案(摘录(。
export const getStaticPaths = async () => {
const database = await getDatabase(databaseId);
return {
paths: database.map((page) => ({ params: { slug: page.properties.Slug.rich_text[0].plain_text } })),
fallback: true,
};
};
export const getStaticProps = async (context) => {
const { slug } = context.params;
const database = await getDatabase(databaseId);
const id = database.find((post) => post.properties.Slug.rich_text[0].plain_text === slug).id;
const page = await getPage(id);
const blocks = await getBlocks(id);
return {
props: {
page,
blocks: blocksWithChildren,
},
revalidate: 1,
};
value.text
->value.rich_text
原因是api的概念发生了变化:https://developers.notion.com/changelog/releasing-notion-version-2022-02-22