herohoroブログ

DBに収納されたPage内に記入したテキストをブログに表示させる~block & block の闇~| Blog learn06



🔄   2023-03-14
No comments to display

いよいよ最後になりました。

振り返ってみると......

  1. レイアウトを再現
    1. ノーマルなcreate-next-appから本家のレイアウトを再現_Blog learn01
  2. APIについて基礎的な実装をして理解
    1. APIのreq/resがいまいち分からないから作って遊んで浸透させることにした_Blog learn02
  3. NotionDBの列の値を記事一覧ページに表示
    1. Notion APIの公式リファレンスを徹底的に根拠付けしながらブログにtitle,text,dateを一覧にして表示させる方法_Blog learn03
  4. 記事一覧ページから記事ページへの遷移
    1. NotionAPIで取得したslugの値で記事リンクを作成する | getStaticPathとDynamic routesが便利だ_Blog learn04
  5. NotionDBの列の値を記事ページに表示
    1. 記事ページにDBの情報を表示させる | useEffect・enableLink_Blog learn05

少しずつeasy-notion-blogっぽくなってきました★

残すは本文を表示させるのみ\(^o^)/

Notionには様々なblockがありますが、

テキストのみを表示させていきます。

テキストを表示させる流れが分かると、

他のblockも応用させて実装できるので、

基本的な部分に絞って説明していきます(*´ω`*)(*´ω`*)

Paragraph blockについて

NotionAPI公式リファレンスのサイドメニューにある【Block object】を開くと説明があります。

image block

https://developers.notion.com/reference/block

Block objectには

  • object:block 👉これは必ずblock
  • id
  • created_time
  • created_by
  • last_edited_time
  • last_edited_by
  • archived
  • has_children
  • type
  • {type}

10項目ある。

blockの種類によって変わるのがtype{type}の部分。

テキスト(paragraph)blockの場合は.....

rich text objectの配列を含めているので、

Paragraph blocksの説明では少し省略されています。

image block

image block
rich text

https://developers.notion.com/reference/rich-text

▼ まとめるとこんな感じ

  • object:block
  • id:
  • created_time:
  • created_by:
    • object:
    • id:
  • last_edited_time:
  • last_edited_by:
    • object:
    • id:
  • has_children:false👉 入れ子があるならtrue(今回しない)
  • type:ブロック種類名 👉 paragraph
  • archived:false
  • ブロック種類名(paragraph):{
    • rich_text:[
      • type: タイプ名👉text
      • タイプ名(text):
        • content:
        • link:
      • annotations:
      • plain_text
      • href:
    • ]
    • checked:false
    • color:default
    • children:[{ 👉 入れ子があるなら追加する(今回しない)
      }]
  • }

Paragraph blockを取得する

取得するためには

  1. 型定義をする_interfaces.ts
  2. 取得するための場合分け_client.tsx
  3. 取得できているか確認_[slug].tsx

型定義をする

easy-notion-blogはTypeScriptなので型定義をinterfaces.tsで行います。

export interface Block {
  Id: string;
  Type: string;
  HasChildren: boolean;
  Paragraph?: Paragraph;
}
src/lib/interfaces.ts

「なんでstring?なんでboolean?」の確認は

Blocks object keysの表にあるType列を参照してください。

https://developers.notion.com/reference/block#block-object-keys

使いたい部分だけを定義していきますーーーー(●´ω`●)

最後のParagraph? の部分はParagraphだったら......

この後に追加するexport interface Paragraph に続きます。

//つづき
export interface Paragraph {
  RichTexts: RichText[];
  Children?: Block[];
}
src/lib/interfaces.ts

ひとまず文字の色などは実装せず純粋なテキストを表示させてみようと思います。

RichTextは配列になっているのでまた追加していきます。

//つづき
export interface RichText {
  Text: Text;
  PlainText: string;
}
src/lib/interfaces.ts

rich textのタイプをtextに指定したので、また後で詳しく追加します。

//つづき
export interface Text {
  Content: string;
}
src/lib/interfaces.ts

取得するための場合分け

client.tsxで必要な情報を仕分けていきます。

interfaces.tsで記述した型定義を取り込み......

import {
  Post,
  Block,
  Paragraph,
  RichText,
  Text
} from "./interfaces";
src/lib/client.tsx

block IDで取得するための関数を用意します。

export async function getAllBlocksByBlockId(blockId) {
  let allBlocks: Block[] = [];
  const params = {
    block_id: blockId
  };
// このあとまだ続けるよ
src/lib/client.tsx

😨
なんでblock IDなの???ページじゃないの???

blockの謎

NotionDBのitemは.....blockとして扱う!!

https://zenn.dev/5t111111/articles/80934cdda55328

Page content はそれを構成するブロックの集合体であり、そのデータを取得するためにはまた別のエンドポイントを使わないといけない、ということです。

blockをあのblockと考えると混乱するので、

ブログのページのことだな....と考えると急に納得してきます。

export async function getAllBlocksByBlockId(blockId) {
  let allBlocks: Block[] = [];
  const params = {
    block_id: blockId
  };
// このあとまだ続けるよ
src/lib/client.tsx さっきのコード

ページ(block)を取得するには

Retrieve block childrenを使っていきます。

image block

childrenは本来のblockのことなのかも....(*´ω`*)(*´ω`*)

リファレンスにあるサンプルコードはこんな感じ

const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_API_KEY });

(async () => {
  const blockId = 'b55c9c91-384d-452b-81db-d1ef79372b75';
  const response = await notion.blocks.children.list({
    block_id: blockId,
    page_size: 50,
  });
  console.log(response);
})();
NotionAPI公式リファレンス/Blocks/Retrieve Block Children サンプルコード

既にClientや環境変数は記述済なので.....

export async function getAllBlocksByBlockId(blockId) {
  let allBlocks: Block[] = [];
  const params = {
    block_id: blockId
  };
    // 👆 ここまで同じ 👇 ここからがサンプルコード参照箇所
	const data = await client.blocks.children.list(params);
  const blocks = data.results.map((item) => {
    const block: Block = {
      Id: item.id,
      Type: item.type,
      HasChildren: item.has_children
    };
//このあとまだ続けるよ
src/lib/client.tsx

const blockの中身はinterfaces.tsで定義した部分と重なる〜

export interface Block {
  Id: string;
  Type: string;
  HasChildren: boolean;
  Paragraph?: Paragraph;
}
既に追記した src/lib/interfaces.ts

型定義にはParagraphについてもあったので、

つづきはParagraphだった場合の記述

//つづき
switch (item.type) {
      case "paragraph":
        const paragraph: Paragraph = {
          RichTexts: item.paragraph.rich_text.map(_buildRichText)
        };
        block.Paragraph = paragraph;
        break;
    }
scr/lib/client.tsx

他にもblockの種類があればcaseで追加していくようだけど、

今回はParagraphのみなので閉じちゃいます。

//つづき
			return block;
  });
  allBlocks = allBlocks.concat(blocks);
  params["start_cursor"] = data.next_cursor;


  return allBlocks;
}
scr/lib/client.tsx

blocksを1つずつ取り出してblockの種類ごとに必要な要素を取得してからallBlocksにしまっちゃう。

params["start_cursor"] = data.next_cursor; は前々回やったPaginationのResponseの要素

image block

https://developers.notion.com/reference/pagination

NotionAPIで取得したslugの値で記事リンクを作成する | getStaticPathとDynamic routesが便利だ_Blog learn04


今回なるべく真偽判定をカット(動くからいいや!という判断...)して説明してしまっていますが、

本来はhas_moreの判定もあります!!!

export async function getAllBlocksByBlockId(blockId) {
  let allBlocks: Block[] = [];
  const params = {
    block_id: blockId
  };
  while (true) { 👉   これ
	  const data = await client.blocks.children.list(params);
	  const blocks = data.results.map((item) => {
    const block: Block = {
      Id: item.id,
      Type: item.type,
      HasChildren: item.has_children
    };
    switch (item.type) {
      case "paragraph":
        const paragraph: Paragraph = {
          RichTexts: item.paragraph.rich_text.map(_buildRichText)
        };
        block.Paragraph = paragraph;
        break;
    }

    return block;
    });

  allBlocks = allBlocks.concat(blocks);
  if (!data.has_more) {   👉  これ
     break;
   }
  params["start_cursor"] = data.next_cursor;
   }

  return allBlocks;
}
src/lib/client.tsx 真偽条件含めたよ

🤔
while (true)って何に対してなのかが謎のままです.....(知ってる人いたら教えて~~~~)
🤔
if(!data.has_more) はpaginationのresponseの要素のhas_moreで最後ならfalseになるってのは分かるんだけど、削除しても動いちゃってるんだよね。。。謎.......


最後にmapの引数の_buildRichTextを記述したら完成★

// つづき
function _buildRichText(item) {
  const text: Text = {
    Content: item.text.content
  };

  const richText: RichText = {
    Text: text,
    PlainText: item.plain_text
  };
  return richText;
}
src/lib/client.tsx

interfaces.tsで定義した部分と見比べてみると.....

export interface RichText {
  Text: Text;
  PlainText: string;
}
export interface Text {
  Content: string;
}
src/lib/interfaces.ts 

同じだねーーー\(^o^)/

取得できているか確認

石橋を叩いて渡る慎重さで進めます。

.....というのも、エラーにハマってだいぶ苦労しました。

console.dir() を使ってちゃんと取得できているかを確認しみます(´・ω・`)

image block

console.dirとは....

console.logはよく耳にします。

実際に使ってみると入れ子になってるNotionAPIの情報を深くまで確認できず困りました。

image block

調べてみると....

2階層までしか表示できないconsole.logを

console.dirにすることで丸っと確認できるってことが分かりました\(^o^)/

console.dir() はオブジェクトを何階層下まで出力するかを第二引数で指定できる模様。第二引数はオプションのオブジェクト。そこに depth: null を指定すると、一番下まで出力してくれる。(デフォルト値は depth: 2)

Node.js の console.log() で [Object] とかの中身を見る方法

👆

こちらの記事、すごく分かりやすかったです。

console.dirを使ってみよう

clientで記述した内容を[slug].tsxで使えるように追加していきます。

// getAllBlocksByBlockIdを追加
import {
  getPostBySlug,
  getAllPosts,
  getAllBlocksByBlockId
} from "../../lib/client";
//他のimportは同じなので省略

// const blocksの行を追加し、propsにblocksを追加
export async function getStaticProps({ params: { slug } }) {
  const post = await getPostBySlug(slug);
  const blocks = await getAllBlocksByBlockId(post.PageId);
  return {
    props: { post, blocks },
    revalidate: 60
  };
}

//export async function getStaticPaths()は同じなので省略

//blocks=[]を追加
const RenderPost = ({ post, blocks = [] }) => {

// console.dirを使いたい場所に追加する
return (
    <div className={styles.container}>
      <div className={styles.mainContent}>
        <p>Post: {slug}</p>
        <PostDate post={post} />
        <PostTitle post={post} enableLink={false} />

        {console.dir(blocks, { depth: null })} 👉 追加

      </div>
    </div>
  );
};

export default RenderPost;
src/pages/blog/[slug].tsx

するとちゃんと取得できているかを確認できます\(^o^)/

image block

上手く取得できていない場合....

私はハマりました。

怪しいparagraphの場合分けの部分に失敗フラグ🚩を追加して確認することで

原因を見つけることが出来ました。

export async function getAllBlocksByBlockId(blockId) {
  let allBlocks: Block[] = [];
  const params = {
    block_id: blockId
  };
  // while (true) {
  const data = await client.blocks.children.list(params);

  const blocks = data.results.map((item) => {
    const block: Block = {
      Id: item.id,
      Type: item.type,
      HasChildren: item.has_children
    };
    switch (item.type) {
      case "paragraph":
        const paragraph: Paragraph = {
          RichTexts: item.paragraph.rich_text.map(_buildRichText)
        };
        block.Paragraph = paragraph;
        break;
//  ▼  paragraphと認識できていなかったら表示させる作戦
        default:
         console.log("失敗....");
//  ▲ ▲ ▲
		}
    return block;
  });
  allBlocks = allBlocks.concat(blocks);
  // if (!data.has_more) {
  //   break;
  // }
  params["start_cursor"] = data.next_cursor;
  // }

  return allBlocks;
src/lib/client.tsx

image block

無事paragraphを取得できたので表示させていきますーーー(*^^*)

Paragraph Blockを表示させるには

NotionDBの列情報を表示させる時は簡単に済ませられましたが、

page内の情報を表示させるにはまたひと手間必要なようです。(^_^;)

流れとしては...

  1. 取得したblocksを1つずつ表示できるようにする_blog-parts.tsx
  2. block専用のcomponentを用意する_notion-block.tsx
  3. 使いたい場所に表示させる_[slug].tsx

取得したblocksから

オブジェクト配列に含まれる配列のみを

結合して整理する......部分で泣きそうになりました(´・ω・`)www

取得したblocksを1つずつ表示できるようにする

componentsフォルダ内のblog-parts.tsxにPostBodyを追加します。

export const PostBody = ({ blocks }) => (
  <div className={styles.postBody}>
    {wrapListItems(blocks).map((block, i) => (
      <NotionBlock block={block} key={`post-body-${i}`} />
    ))}
  </div>
);
src/components/blog-parts.tsx

まだ記述していない関数もありますが、

ざっくり見てみると......

取得したblocksを1つずつmapで取り出してNotionBlockコンポネントで処理しているのが分かります。

wrapListItemsをPostBodyの上に追加します。

const wrapListItems = (blocks) =>
  blocks.reduce((arr, block) => {
    return arr.concat(block);
  }, []);

//この後PostBodyの記述が始まる
src/components/blog-parts.tsx

🤔
reduce()ってなんじゃ?????

reduce()とは....

Mdn Web Docsを参照すると、

リストの値を1つずつ処理していっている....

image block

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#初期値がある場合の_reduce_の動作

wrapsListItemに置き換えて考えてみる.....

const wrapListItems = (blocks) =>
  blocks.reduce((arr, block) => {
    return arr.concat(block);
  }, []);

//この後PostBodyの記述が始まる
src/components/blog-parts.tsx

  • previousVelue:arr
  • currentValue:block
  • 処理:return arr.concat(block)
  • 初期値:[]

🤔
ん???なんか違う......

image block

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#二次元配列を一次元配列にする

blocksが二次元配列だったのかを確認してみると.....

[
  {
    Id: '0b0****************',
    Type: 'paragraph',
    HasChildren: false,
    Paragraph: {
      RichTexts: [
        {
          Text: {
            Content: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
          },
          PlainText: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
        }
      ]
    }
  },
  {
    Id: '3d6*******************',
    Type: 'paragraph',
    HasChildren: false,
    Paragraph: { RichTexts: [] }
  },
  {
    Id: '7b********************',
    Type: 'paragraph',
    HasChildren: false,
    Paragraph: {
      RichTexts: [ { Text: { Content: '2つ目テキスト' }, PlainText: '2つ目テキスト' } ]
    }
  }
]
blocksをconsole.dirで確認
🤔
......??

もう少し解説記事読み進めていくと....

// friends - an array of objects
// where object field "books" is a list of favorite books
let friends = [{
  name: 'Anna',
  books: ['Bible', 'Harry Potter'],
  age: 21
}, {
  name: 'Bob',
  books: ['War and peace', 'Romeo and Juliet'],
  age: 26
}, {
  name: 'Alice',
  books: ['The Lord of the Rings', 'The Shining'],
  age: 18
}]

// allbooks - list which will contain all friends' books +
// additional list contained in initialValue
let allbooks = friends.reduce(function(previousValue, currentValue) {
  return [...previousValue, ...currentValue.books]
}, ['Alphabet'])

// allbooks = [
//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
//   'Romeo and Juliet', 'The Lord of the Rings',
//   'The Shining'
// ]
サンプル

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce#スプレッド演算子と_initialvalue_を使ってオブジェクトの配列に含まれる配列を結合させる

😙
スプレッド演算子の部分は違うけど近い感じがしてきたーーーー

returnの[...previousValue, ...currentValue.books]はfriendsのbooksの値を指定してる!!

booksのみをくっつけていったら....

[ ]が入っていたはずだけど入れずに羅列していくのがreduceってやつなのかな...。

// allbooks = [
//   'Alphabet',  ['Bible', 'Harry Potter' ],  ['War and peace',
//   'Romeo and Juliet' ],  ['The Lord of the Rings',
//   'The Shining' ]
// ]
👇
// allbooks = [
//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace',
//   'Romeo and Juliet', 'The Lord of the Rings',
//   'The Shining'
// ]
reduce 前と後

入れ子になっているbooksの値がリストになって整頓できるってことだから、

blocksの場合に置き換えて考えてみると.....

const wrapListItems = (blocks) =>
  blocks.reduce((arr, block) => {
    return arr.concat(block);
  }, []);

//この後PostBodyの記述が始まる
src/components/blog-parts.tsx
  • previousVelue:arr
  • currentValue:block
  • 処理:return arr.concat(block)
  • 初期値_無し:[]

  [{
    Id: '0b0****************',
    Type: 'paragraph',
    HasChildren: false,
    Paragraph: {
      RichTexts: [
        {
          Text: {
            Content: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
          },
          PlainText: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
        }
      ]
    }
  },
{
//つづく....
reduce前のblocksをconsole.dirで確認
🤔
ん??

😱
reduce後のblocksをconsole.dirで確認しなきゃだ....

確認するためには....

wrapListItemsがどんな結果になっているのかを知りたい。

🤔
PostBodyをもとに確認用のコンポネントをつくってみよう....
const wrapListItems = (blocks) =>
  blocks.reduce((arr, block) => {
    return arr.concat(block);
  }, []);  //  👉 この[ ]を確認したい...

export const PostBody = ({ blocks }) => (
  <div>
    {wrapListItems(blocks).map((block, i) => (
      <NotionBlock block={block} key={`post-body-${i}`} />
    ))}
  </div>
);
src/components/blog-parts.tsx 現状

// PostBodyの後に追記
export const PostBodyTest = ({ blocks }) => (
  <div>
    {wrapListItems(blocks).map((block) => console.dir(block, { depth: null }))}
  </div>
);
src/components/blog-parts.tsx 追加

mapでwrapListItemsの中身[ ]を1つずつ取り出すconsoleを作ってみた。

{
  Id: '0b*******************',
  Type: 'paragraph',
  HasChildren: false,
  Paragraph: {
    RichTexts: [
      {
        Text: {
          Content: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
        },
        PlainText: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
      }
    ]
  }
}
{
  Id: '3************************',
  Type: 'paragraph',
  HasChildren: false,
  Paragraph: { RichTexts: [] }
}
{
  Id: '7b**********************',
  Type: 'paragraph',
  HasChildren: false,
  Paragraph: {
    RichTexts: [ { Text: { Content: '2つ目テキスト' }, PlainText: '2つ目テキスト' } ]
  }
}
wrapListItemsでreduce処理をした後の情報を1つずつ取った結果

map前のwrapListItemsの姿は...

1つずつ[ ]に戻した形...

reduce処理の前と同じだ....。

🤔
wrapListItemsをしないままPostBodyコンポネントを動かしたらどうなるんだろう...

冒険:reduceせずにPostBodyコンポネントで処理してみる

とりあえず、PostBodyTestコンポネントのようなconsoleを作ってみると....

export const PostBodyNoReduce=({blocks})=>{
  const noreduce={blocks}
  return(
  <div>
    {noreduce.map((block)=>console.dir(block,{depth:null}))}
  </div>
  )
}
src/components/blog-parts.tsx   wrapListItemsを使わずになんちゃってPostBodyTestを作ってみる.

Σ(゚Д゚)Σ(゚Д゚)

mapがエラー.....TypeError: noreduce.map is not a function

🤔
mapを動かすためにwrapListItemsの処理が必要なのか....


出直しますーーーーm(_ _)m

処理する前の[ ]ってreduceで収納してる[ ] と意味違うのかな??.... 05/22


PostBodyコンポネントを整理

wrapListItemsを使って

mapで1つずつ取り出しながらNotionBlockコンポネントに処理を投げます。

const wrapListItems = (blocks) =>
  blocks.reduce((arr, block) => {
    return arr.concat(block);
  }, []);

//  ▼  これ
export const PostBody = ({ blocks }) => (
  <div className={styles.postBody}>
    {wrapListItems(blocks).map((block, i) => (
      <NotionBlock block={block} key={`post-body-${i}`} />
    ))}
  </div>
);
src/components/blog-parts.tsx 完成

これで取得したblocksを1つずつ表示できるようにすることができました\(^o^)/

まだ終わりではない....

(ツライね。)

block専用のcomponentを用意する

componentsフォルダにnotion-block.tsxを用意します。

paragraphの場合に処理する内容を記述.....

const NotionBlock = ({ block }) => {
  if (block.Type === "paragraph") {
    return <Paragraph block={block} />;
  }
  return null;
};
export default NotionBlock;
src/components/notion-block.tsx

paragraphの場合にParagraphコンポネントを使う。

const Paragraph = ({ block }) => (
  <p>
    {block.Paragraph.RichTexts.map((richText, i) => (
      <RichText richText={richText} key={`paragraph-${block.Id}-${i}`} />
    ))}
  </p>
);
// このあと NotionBlockの記述が始まる
src/components/notion-blocks.tsx

ちょっとblockを確認

[
//  ▼ block でまとめられている{}の部分
  {
    Id: '0b0***************',
    Type: 'paragraph',
    HasChildren: false,
    Paragraph: {
      RichTexts: [
        {
          Text: {
            Content: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
          },
          PlainText: 'テキストをnotionAPIを使ってブログを作る方法というタイトルのページ内に入力。'
        }
      ]
    }
  },
blocksをconsole.dirで確認

mapで1つずつRichTextsの要素(Text・PlainText)を取って生きながらRichTextコンポネントに投げてる!!

RichTextコンポネントも追加

const RichText = ({ richText }) => {
  let element = richText.Text.Content;
  return element;
};
//このあと Paragraphコンポネントの記述がはじまる

Contentの内容を返してる!!

これでやっと

blog-parts.tsxで記述したPostBodyコンポネントを

使えるようになりました\(^o^)/

2つのコンポネントファイルをつなげる

blog-parts.tsxにNotionBlockをimport

import NotionBlock from "./notion-block";
src/components/blog-parts.tsx

notion-block.tsxにはReactをimport

import React from "react";
src/components/notion-blocks.tsx

これでOK\(^o^)/

使いたい場所に表示させる

ここからはいつもと同じ流れ。

使いたい場所である[slug].tsxに必要なPostBodyコンポネントを追加でimport

import {
  PostDate,
  PostTitle,
  PostBody
} from "../../components/blog-parts";
src/pages/blog/[slug].tsx

const RenderPost = ({ post, blocks = [] }) => {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div className={styles.container}>
      <div className={styles.mainContent}>
        <p>Post: {slug}</p>
        <PostDate post={post} />
        <PostTitle post={post} enableLink={false} />

        <PostBody blocks={blocks}/>  ***  👉 これ追加   ***
       
      </div>
    </div>
  );
};
src/pages/blog/[slug].tsx

出てきたーー\(^o^)/\(^o^)/

image block

まとめ

取得する

  1. 型定義をする_interfaces.ts
  2. 取得するための場合分け_client.tsx
    1. ページをblockとして捉える
    2. ページを取得するにはRetrieve block children
  3. 取得できているか確認_[slug].tsx
    1. condole.dir()を使う

表示させる

  1. 取得したblocksを1つずつ表示できるようにする_blog-parts.tsx
    1. reduce()を使って整理する
  2. block専用のcomponentを用意する_notion-block.tsx
    1. 2つのコンポネントファルをつなげる
  3. 使いたい場所に表示させる_[slug].tsx

今回使用したcode sandboxはこちら

https://codesandbox.io/embed/slug-block-paragraph-825ojw?fontsize=14&hidenavigation=1&theme=dark

GitHubリポジトリに収納済です\(^o^)/

No.branchdescriptionリンクPR
7rseo19API routing _入力フォームhttps://github.com/herohoro/Blog_learn/pull/9#9
8rw064kData fetching _収納したディレクトリからテキストデータを表示_libhttps://github.com/herohoro/Blog_learn/pull/10#10
99cp6j7NotionAPIからDBのタイトル・テキスト・日付列を表示させる_他_lib/環境変数module/getStaticProps/propshttps://github.com/herohoro/Blog_learn/pull/11#11
10oek04hslugを使って画面遷移_getStaticPathhttps://github.com/herohoro/Blog_learn/pull/12#12
11oek04h修正_画面遷移のエラーを解消https://github.com/herohoro/Blog_learn/pull/13#13
12zz22j8DB列のタイトル・日付を記事ページに表示させるhttps://github.com/herohoro/Blog_learn/pull/15#15
13825ojwNotionDBのpage内テキストを表示させるhttps://github.com/herohoro/Blog_learn/pull/16#16

リンク列のPRページへ行くと、コメント内に解説記事も追記してます。

このブログ(Blog learnタグ)からでも

作成過程を追えるようになっているので活用してみてくださいーーー


本文を表示させるのが予想以上に難しくて

だいぶ格闘しました(´・ω・`)(;・∀・)

実際はparagraphブロックだけではなく

いろいろな種類のブロックを場合分けしながら

取得・表示させているアルパカ先生は本当すごい方だなと

思うと同時に、

「いったいどんなスキルを積んだらこんな記述を使いこなせるの?」

と驚かされるばかりでした。

見た目は質素で実用的なレベルとは程遠いBlog Learnの実装レベルですが、

この調子で作り込んでいくには....

いったい何日かかるのやらです。

OSSありがたき。

easy-notion-blogバンザイです。

(*´ω`*)(*´ω`*)🚩

途中とっちらかった説明をしてる部分があったかと思います。

私一人では手に負えなかった.....

分かり次第修正して完成させていく予定です。

Twitterで教えてくれると嬉しいです🙌

Twitterでは更新のお知らせを随時行っています

興味ある方はLet'sフォロー★

▼ この記事に興味があったら同じタグから関連記事をのぞいてみてね

Buy Me A Coffee

新着記事を通知したい??


RSSリーダーにatomのリンクを登録すると通知が行くよ🐌

https://herohoro.com/atom

やってみてね(*´ω`*)(*´ω`*)

Twitter Timeline


フォロー大歓迎\(^o^)/