Next.jsとMicroCMSでブログサイトを作成するーPart2（基本編）

[Next.jsとMicroCMSでブログサイトを作成するーPart1（準備編）](https://qiita.com/qn-takami/items/e6c72e1688fd1cc5af18)の続きです。

:::note info
こちらも合わせてどうぞ
[Next.jsとMicroCMSでブログサイトを作成するーPart1（準備編）](https://qiita.com/qn-takami/items/e6c72e1688fd1cc5af18)
[Next.jsとMicroCMSでブログサイトを作成するーPart3（応用編）](https://qiita.com/qn-takami/items/7f528acfaf750b029088)
:::

## Next.jsアプリからmicroCMSのブログデータを取得して表示しよう

アプリケーションのTOPページにブログの一覧が表示されるようにしましょう。完成形はこちらです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821455/cde7c08b-5a2a-1cf5-6840-5ca016b5f115.png)

## ブログ記事一覧を作成する
TOPページは pages/index.js を以下のように書き換えます。

```pages/index.js
import Head from "next/head";
import Link from "next/link";
import styles from "@/styles/Home.module.css";
import { client } from '@/libs/client'
export default function Home({ blog }) {
  return (
    <>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
        {blog.map((blog) => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>{blog.title}</Link>
          </li>
        ))}
      </main>
    </>
  )
}
export const getStaticProps = async () => {
  const data = await client.get({
    endpoint: 'blogs',
  })
  return {
    props: {
      blog: data.contents,
    },
  }
}
```

ちなみにこのままだと、ブログ一覧についたリンクをクリックしても404エラーになります。後ほどブログ詳細ページも追加します。

:::note info
React/Next.jsの書き方
- 基本的にHTML部分とアクション、CSS部分は分離する
- アクション部分はfunctionなど関数化
- HTML部分はreturnで記載
- export default functionでファイル全体を関数にする
- 必要なライブラリやコンポーネントは import する

一般的なファイルの構成は以下のようになります。これを頭に入れつつコードを解読してみましょう。

```
import Link from "next/link"; // Linkライブラリを読み込み
import styles from "@/styles/Home.module.css"; // CSS
import { client } from '@/libs/client' // microCMSアクセスのためのライブラリを読み込み
export default function Home({ blog }) { // ここからが機能のメイン
  async function create(event) {
    // 下記のHTMLからのFormのアクション内容
  }
  return (
    <>　// フラグメント
      // 表示されるHTML
    </>
  )
}
export const getStaticPaths = async () => {
　　// 現状のURLのパスから情報を取得
};
export const getStaticProps = async (context) => {
 // Prop の取得
};
```
:::

getStaticPropsという関数を作成してmicroCMSよりブログデータを抽出しています。 async は非同期処理を行う関数で、その中で await で個々の処理を待機するという処理を行っています。

また、スタイルシートも修正します。liタグの行間（padding）が広く表示されてしまうので、以下の部分を削除します。

```styles/Home.module.css
.main {
  display: flex;
  flex-direction: column;
-  justify-content: space-between;
  align-items: center;
  padding: 6rem;
  min-height: 100vh;
}
```

ここまで修正したら以下のコマンドでアプリを立ち上げます。なお、この後に紹介するVSCodeのデバッグを使う方法であればコマンドを気にせずボタンだけでサーバーの立ち上げが可能です。

```
npm run dev
```

http://localhost:3000 を起動してみましょう。以下のように表示されれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821455/8d7274b9-e701-c945-e29a-b7e3a87cd5d7.png)

うまく以下ない場合は以下の注意点を参考にしてみてください。

### 注意点
- 環境変数のAPI_KEYやSERVICE_DOMAINが間違ってないかを確認
- APIのENDPOINT（今回はblog）が間違ってないか確認
- liタグで出力しているidやtitleといったカラム名が間違ってないか

## 記事を表示する
次に各記事を表示するロジックを記載します。 pages ディレクトリの下に blog というディレクトリを作成して下記のファイルを置きます。ファイル名はこのまま [id].js にしてください。この [id] は自動にブログのIDが入ります。

```pages/blog/[id].js
import { client } from "../../libs/client";
import { DateTime } from 'luxon' // 日時のフォーマット用
export default function BlogId({ blog }) {
  return (
    <main>
      <h1>{blog.title}</h1>
      <p>{DateTime.fromISO(blog.publishedAt).setZone("utc").toLocaleString(DateTime.DATE_FULL)}</p>
      <p>{blog.content.ca</p>
      <div
        dangerouslySetInnerHTML={{
          __html: `${blog.content}`,
        }}
      />
    </main>
  );
}
export const getStaticPaths = async () => {
  const data = await client.get({ endpoint: "blogs" });
  const paths = data.contents.map((content) => `/blog/${content.id}`);
  return { paths, fallback: false };
};
export const getStaticProps = async (context) => {
  const id = context.params.id;
  const data = await client.get({ endpoint: "blogs", contentId: id });
  return {
    props: {
      blog: data,
    },
  };
};
```

記事公開日(publishedAt)を日付表記を修正するために luxon というライブラリを使用しています。

また dangerouslySetInnerHTML というReactのライブラリを使用してHTMLを表示しています。今回は話を簡単に紹介するために使っておりますが、XSSを誘発するスクリプトなので使い方には注意しましょう。

こちらの記事の方のgetStaticProps では id もキーにして取得しています。あとは上のブログ一覧と同じです。

これでサーバーを立ち上げると以下の表に表示されるはずです（MicroCMSで入稿してある前提）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821455/99e94a60-ead3-4b9c-b4f9-34d900e64d91.png)

### 【参考】VSCode使ったデバッグの方法
IDEとしてVSCodeを使用することをオススメします。以下のリンクよりインストールしてみてください。

[Visual Studio Code – コード エディター | Microsoft Azure ](https://azure.microsoft.com/ja-jp/products/visual-studio-code)

VSCodeでNext.jsをデバッグするには以下の設定が必要です。プロジェクト直下にファイルを置いてください。

```.vscode/launch.json
{
    "version": "0.2.0",
    "configurations": [
      {
        "name": "Next.js: debug server-side",
        "type": "node-terminal",
        "request": "launch",
        "command": "npm run dev"
      },
      {
        "name": "Next.js: debug client-side",
        "type": "pwa-chrome",
        "request": "launch",
        "url": "http://localhost:3000"
      },
      {
        "name": "Next.js: debug full stack",
        "type": "node-terminal",
        "request": "launch",
        "command": "npm run dev",
        "console": "integratedTerminal",
        "serverReadyAction": {
          "pattern": "started server on .+, url: (https?://.+)",
          "uriFormat": "%s",
          "action": "debugWithChrome"
        }
      }
    ]
  }
```
使い方は以下の画像を参考にしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821455/b5620e37-ff3f-6bdd-44bf-b44c189181fc.png)

デバック操作はブレークポイントを気になる箇所に貼りながらブラウザ表示して操作していくと良いと思います。デバッグ操作はこちらと書いてあるツールボックスから1行ずつ実行したり、変数をマウスオーバーして中身を見るということができるのでぜひご活用ください。

## 記事を作成する
ここまではmicroCMSに元から作ってある記事について公開していました。普通にブログであればそれでOK（公開して表示するだけなので）ですが、ユーザー側から記事を投稿できるようフォームを作成してみましょう。下記のファイルを作成します。新規記事作成フォームになります。

フォームのイメージはこちらです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821455/a13aeb62-378b-a096-6c02-4c55d90ce387.png)

ソースは以下のようになります。

```pages/blog/create.js
import Link from "next/link";
import { client } from "../../libs/client";
import { useRouter } from "next/router";
export default function Create () {
    const router = useRouter()
    async function create(event) {
      event.preventDefault()
      const formData = new FormData(event.currentTarget);
      const title = formData.get("title");
      const content = formData.get("content");
      client.create({
        endpoint: "blogs",
        content: {
          title: title,
          content: content,
        }
      }).then((res) => {
        if (res.status === 401) {
          alert("登録ができませんでした。")
        } else {
          alert("登録されました。")
          router.push(`/`)
        }
      })
    }
  return (
    <>
      <div className='main'>
        <h1 className=''>投稿ページ</h1>
        {/* TOPに戻るボタン */}
        <div className="top">
          <Link href="/" className="">
            <button className="">Topに戻る</button>
          </Link>
        </div>
        <div className="contents">
            <div>
                <form onSubmit={ create }>
                  <div>
                      <h2>タイトル</h2>
                      <input name="title" type="text" />
                  </div>
                  <div>
                  <h2>コンテンツ</h2>
                      <textarea name="content" ></textarea>
                  </div>
                <button type="submit">
                    <p>登録する</p>
                </button>
                </form>
            </div>
        </div>
      </div>
    </>
  );
}
```

8行目の event.preventDefault()  はFormタグがAction先を明示してないと現在のページに対してActionしてしまって画面がリロードされてしまうためそれを防いでいます。10行目のFormData(event.currentTarget)はFormのデータを取得しています。15行目から29行目でmicroCMSのライブラリ使って記事をCreateしています。

45行目からは実際に表示するフォームになります。

記事の編集、削除は[Next.jsとMicroCMSでブログサイトを作成するーPart3（応用編）](https://qiita.com/qn-takami/items/7f528acfaf750b029088)に続きます。