ブログ用に用意しているNotionデータベースにslug列を追加します。
作りたいのはこんな感じ
表示させるのは前回の記事を元にするとすぐ実装できそう⭐
https://herohoro.com/blog/blog-learn_notion-api-read
lib/interfaces.ts
に追加lib/client.ts
で追加components/blog-parts.tsx
に追加pages/blog/index.tsx
にcomponentを追加export interface Post {
PageId: string;
Title: string;
Excerpt: string;
Date: string;
Slug: string;👉追加
}
//省略
function _buildPost(data) {
const prop = data.properties;
const post: Post = {
PageId: data.id,
Title: prop.Title.title[0].plain_text,
Excerpt: prop.Excerpt.rich_text[0].plain_text,
Date: prop.Date.date.start,
Slug: prop.Slug.rich_text[0].plain_text 👉追加
};
return post;
//postに収納
}
//省略
export const PostSlug = ({ post }) => <p>{post.Slug ? post.Slug : ""}</p>; 👉追加
//省略
const RenderPosts = ({ posts = [] }) => {
return (
<div className={styles.container}>
<div className={styles.mainContent}>
<p>***main-content***</p>
<h2>BlogList page</h2>
<br />
{""}
<section>
<div>
{/* 変数postsを1つの塊ごと取り出していく */}
{posts.map((post) => {
return (
<div key={post.Date}>
<PostDate post={post} />
<PostTitle post={post} />
<PostExcerpt post={post} />
<PostSlug post={post} /> 👉追加
</div>
);
})}
</div>
</section>
<br />
</div>
<div className={styles.subContent}>
<p>***sub-content***</p>
</div>
</div>
);
};
export default RenderPosts;
https://codesandbox.io/embed/slug-read-syy3lk?fontsize=14&hidenavigation=1&theme=dark
1つのファイルを使い回すDynamic Routesという実装をしていきます\(^o^)/
https://nextjs.org/docs/routing/dynamic-routes
pages/blogフォルダ内
に[slug].tsx
を用意するimport { useRouter } from "next/router";
import styles from "../../styles/blog.module.css";
const RenderPost = (post) => {
const router = useRouter();
const { slug } = router.query;
return (
<div className={styles.container}>
<div className={styles.mainContent}>
<p>Post: {slug}</p>
</div>
</div>
);
};
export default RenderPost;
こんな感じに表示したい.....
そのためには......
https://nextjs.org/docs/basic-features/data-fetching/get-static-props
NotionAPIから取得したデータをいざ使うぜっていうときには
getStaticProps
を本編(今回でいうとRenderPost)の前に記述します。
client.ts
にgetPostBySlug
を追加pages/blog/[slug].tsx
のgetStaticProps
に追加//省略
export async function getPostBySlug(slug: string) {
const data = await client.databases.query({
database_id: DATABASE_ID,
filter: {
property: "Slug",
rich_text: {
equals: slug
}
}
});
return _buildPost(data.results[0]);
}
import { useRouter } from "next/router";
import { getPostBySlug } from "../../lib/client";
import styles from "../../styles/blog.module.css";
export async function getStaticProps({ params: { slug } }) {
const post = await getPostBySlug(slug);
return {
props: { post },
revalidate: 60
};
}
const RenderPost = (post) => {
//省略
https://nextjs.org/docs/basic-features/data-fetching/get-static-paths
Dynamic RoutesのpageでgetStaticProps
を使うなら、pathの一覧をを定義するgetStaticPaths
は必要。
client.ts
にgetAllPosts
を追加lib/blog-helpers.ts
に追加pages/blog/[slug].tsx
のgetStaticPaths
を追加export async function getAllPosts() {
let results = [];
const params = {
database_id: DATABASE_ID,
page_size: 100
};
const data = await client.databases.query(params);
results = results.concat(data.results);
params["start_cursor"] = data.next_cursor;
return results.map((item) => _buildPost(item));
}
getPosts
と何が違うの??export async function getPosts() {
const params = {
database_id: DATABASE_ID
};
const data = await client.databases.query(params);
return data.results.map((item) => _buildPost(item));
}
export async function getAllPosts() {
let results = [];
const params = {
database_id: DATABASE_ID,
page_size: 100
};
const data = await client.databases.query(params);
results = results.concat(data.results);
params["start_cursor"] = data.next_cursor;
return results.map((item) => _buildPost(item));
}
data.results
を収納してる.....https://developers.notion.com/reference/property-item-object#paginated-property-values
だからなに?って感じなのでよくよく調べてみると.....
こんなリファレンスを発見しました🤦♀️
https://developers.notion.com/reference/pagination
objectの一覧を返すエンドポイントでは、Paginationが使われる。
Pagenationにより、APIはリストの一部をリクエストし、結果の配列(array)とnext_cursor
をレスポンスで受け取ることが可能になる。
APIは、他のリクエストでリストの次の部分を受け取るためにnext_cursor
を使用できる。
このテクニックを使って、APIはリスト全体 (または必要な部分だけ) を受け取るようにリクエストし続けることが可能。
※ リクエスト・リスポンスという表現が分かりにくい方はBlog learn02を参照ください
もういちどgetAllPostsを確認....
export async function getAllPosts() {
let results = [];
const params = {
database_id: DATABASE_ID,
page_size: 100
};
const data = await client.databases.query(params);
results = results.concat(data.results);
params["start_cursor"] = data.next_cursor; 👉ここ
return results.map((item) => _buildPost(item));
}
Requestsにはstart_cursorとpage_sizeがある。
start_cursorはデフォルトでは一番目のデータを示す。
次のページのrequestで使うとき、直前のresponseから返ってきたcorsorになる。
start_cursor
にnext_cursor
を代入してたよな......next_cursorってどこにあるんだ???Responsesにnext_cursor
を発見!!!
ついでにさっき「だからなに?」ってなってしまったresults
もある!!!
▼ next_cursorについて.....
同じエンドポイントに start_cursor パラメータとして値を渡すことで、次のページの結果を取得するために使用される。
start_cursorは直前の値。
next_cursorの値としてstart_cursorを更新してあげれば
次のデータがrequestされたことになる
\(^o^)/わんこそばみたい\(^o^)/
▼ resultsについて.....
Pagenationの出だしに説明されていた、
Pagenationにより、APIはリストの一部をリクエストし、結果の配列(array)とnext_cursor
をレスポンスで受け取ることが可能になる。
って部分。
この配列ってresultsのことを意味している\(^o^)/
その上でもう一度getAllPostsを眺めてみる.....
export async function getAllPosts() {
let results = [];
const params = {
database_id: DATABASE_ID,
page_size: 100
};
const data = await client.databases.query(params);
results = results.concat(data.results);
params["start_cursor"] = data.next_cursor; 👉ここ
return results.map((item) => _buildPost(item));
}
いい景色だ.....(*´ω`*)(*´ω`*)💚
lib/blog-helpers.ts
に追加pages/blog/[slug].tsx
のgetStaticPaths
を追加ブラケットで囲ってパスを記述します。
https://nextjs.org/docs/routing/introduction#dynamic-route-segments
//省略
export const getBlogLink = (slug: string) => {
return `/blog/${slug}`;
};
import { getPostBySlug, getAllPosts } from "../../lib/client"; //getAllPosts追加
import { getBlogLink } from "../../lib/blog-helpers";
//他のimportは同じなので省略
//同じなので省略 export async function getStaticProps
export async function getStaticPaths() {
const posts = await getAllPosts();
return {
paths: posts.map((post) => getBlogLink(post.Slug)),
fallback: "blocking"
};
}
//同じなので省略 const RenderPost
↓
すると表示される\(^o^)/
https://codesandbox.io/embed/slug-read-router-9e1fbm?fontsize=14&hidenavigation=1&theme=dark
記事一覧ページに表示されるタイトルにリンクを埋め込み、
手打ちをしなくても記事固有のページへ移動できるようにしてみます(*´∀`*)
components/blog-parts.tsx
に追加import Link from "next/link";
import { getDateStr, getBlogLink } from "../lib/blog-helpers"; // getBlogLinkを追加
//他のimportは同じなので省略
export const PostTitle = ({ post }) => {
const postTitle = post.Title ? post.Title : "";
return (
<h3>
<Link href="/blog/[slug]" as={getBlogLink(post.Slug)} passHref>
<a>{postTitle}</a>
</Link>
</h3>
);
};
//他の export constは同じなので省略
slugをリンクに追加されるように設定したこれ👇
//省略
export const getBlogLink = (slug: string) => {
return `/blog/${slug}`;
};
https://nextjs.org/docs/api-reference/next/link
href:pathかURL
as:ブラウザ上のURLに表示されるpath
passHref:hrefを子要素にする
もう一度該当するコードを確認すると.....
<Link href="/blog/[slug]" as={getBlogLink(post.Slug)} passHref>
<a>{postTitle}</a>
</Link>
/blog/[slug]
というパス//省略
export const getBlogLink = (slug: string) => {
return `/blog/${slug}`;
};
/blog/slug列の値
としたブラウザ上URLのpathslugの値が【notion-api_make-blog】の場合、
/blog/notion-api_make-blog
となる記述だ\(^o^)/
リンクの埋め込まれている記事タイトルをクリックすると.......
表示された\(^o^)/
今度は手打ちしないでOK〜〜〜〜〜
lib/interfaces.ts
に追加lib/client.ts
で追加components/blog-parts.tsx
に追加pages/blog/index.tsx
にcomponentを追加pages/blogフォルダ内
に[slug].tsx
を用意するclient.ts
にgetPostBySlug
を追加pages/blog/[slug].tsx
のgetStuticProps
に追加client.ts
にgetAllPosts
を追加lib/blog-helpers.ts
に追加pages/blog/[slug].tsx
のgetStuticPaths
を追加components/blog-parts.tsx
に追加今回PRして追加したのは#12です\(^o^)/
エラーがあり、後日修正した分は#13にあります。
No. | branchName | description | リンク | PR |
---|---|---|---|---|
10 | oek04h | slugを使って画面遷移_getStaticPath | https://github.com/herohoro/Blog_learn/pull/12 | #12 #13 |
11 | 次回\(^o^)/ | 記事固有ページにDBのタイトル・日付を表示させる_useEffect |
https://github.com/herohoro/Blog_learn/wiki
次回はNotionデータベースのpage内データを取得してブログの記事として表示する流れを解説していきます\(^o^)/
調べれば調べるほどNotionAPIリファレンス見方が分かってきて、
見れば見るほど「んぐぁ~」となるeasy-notion-blogリボジトリ。
APIに初めて触れる人間にとって
面白くてたまらない体験でした。
取得データは同じでも、
見せ方によって七変化なところが面白い。
APIってすごいやー。
とリビングの片隅で余韻に浸るへろほろなのでした。。。。。(*´∀`*)
▼ この記事に興味があったら同じタグから関連記事をのぞいてみてね
RSSリーダーにatomのリンクを登録すると通知が行くよ🐌
https://herohoro.com/atom
やってみてね(*´ω`*)(*´ω`*)
フォロー大歓迎\(^o^)/
フォロー大歓迎\(^o^)/