microCMSのプレビュー機能をGatsby.jsで使う

Gatsby.jsは言わずと知れたReact製の静的サイトジェネレーターですが、ビルド時にページを生成するという性質ゆえに、microCMSのプレビュー機能を使うにはひと工夫必要だったので共有したいと思います。
この機能をご存知の方はコードの部分からご覧ください。
## microCMSの記事プレビュー機能について
microCMSのプレビュー機能について少し説明しておくと、記事執筆画面で
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472897/a27767ac-ea84-2ae3-0f59-376cf66dc606.png)
公開ボタンの左にある画面プレビューを押した時に、執筆中の記事が実際にはどのように表示されるか確認できる機能です。仕組みとしては、

- 「画面プレビュー」をクリック
- 予め設定しておいたURLの変数部分（contentsIdとdraftKey）がクリックした記事のものに置き換えられたURLにアクセス
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472897/395dec17-6792-ffb5-27fa-6bd6116e772f.png)

という感じです。
詳しくはhttps://microcms.io/blog/draftkey_and_preview/ に掲載されています。
###　何が問題でどうしたらいいのか？
この機能をGatsbyで使用する時、考えなければならないのは、Gatsby.jsの記事データは基本ビルド時に生成された物なので、
**「画面プレビュー」クリック時に送られてきた`contentId`と`draftKey`を基に記事データをリアルタイムに取得して、表示する仕組みを作らないといけない。**ということです。
##　ということでコード
前置きはそのくらいにしてコードはこのようになりました。

```pages/previewPage.jsx
import React, { useState, useEffect } from "react";
import { getSearchParams } from "gatsby-query-params";
//...その他コンポーネントなど

function previewPage() {
  //microCMS側に設定するurlはhttps://xxxxxx.com/previewPage/?contentId={CONTENT_ID}&draftKey={DRAFT_KEY}みたいな感じ
  const queryParams = getSearchParams();

  //queryParamsには
  //{contentId:"xxxx",
  //draftKey:"xxxx"}
  //というようなデータが入ります。

  const contentId = queryParams.contentId;
  const draftKey = queryParams.draftKey;

  const [postData, setPostData] = useState(null);//最初、postDataにはnullが入ります。
  
  useEffect(() => {
    if (!postData) {
      fetch(
        `https://xxxxxxxxx.microcms.io/api/v1/blogs/${contentId}?draftKey=${draftKey}`,
        {
          headers: {
            "X-API-KEY": "xxxxxxx-xxxx-xxxxx-xxxx-xxxxxxxx",
          },
        }
      )
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
        })
        .then((json) => {
          postData = setPostData(json);//ここで、postDataに取得したコンテンツが格納されます。
        });
    } else {
      return function cleanup() {
        console.log("done");
      };
    }
  });
  return (
        <div
          dangerouslySetInnerHTML={{
            __html: postData ? postData.sentence : "",
          }}
        ></div>
  );
}

export default previewPage;
```
このようなページを作成することで、アクセスした時にurlクエリパラメータの情報を基にコンテンツをとってきてくれます。
以下、詳しく説明していきます。
### API部分について
microCMSはPOSTとGETのAPI-KEYが違うのでGETのAPIが露出しても大して問題はないですが、なんとなく気持ちが悪いので、
X-API-KEY: "xxxxx-xxxx"としている部分とmicroCMSのurl部分は実際には環境変数に置き換えるのが望ましいです。環境変数の使い方に関しては[こちら](https://qiita.com/yutopia898/items/653068aa3d8237f3e89a)の記事の中でも説明しているので是非ご覧ください。

## `gatsby-query-params`について
2行目に登場する`gatsby-query-params`は[こちら](https://www.npmjs.com/package/gatsby-query-params)です。
使用するにはターミナルで`npm i gatsby-query-params`してください。

コメントアウト部分にもありますが、`getSearchParams`によって、urlクエリパラメータの情報を`queryParams`にオブジェクト形式で格納しています。

## `useState` `useEffect`について
これらはReactのhookで、詳しい説明は[こちら](https://ja.reactjs.org/docs/hooks-effect.html)にあります。
`useEffect`の中で、↑で取得したクエリパラメータを基にmicroCMSにデータを取得しにいき、取得できたら、それを`postData`に格納しています。
###`responce.ok`について
これがないとmicroCMSのレスポンスが404の時(useStateがnullの間)返ってくる空文字列`""`を処理しようとしてしまい、jsonオブジェクトでないのでエラーが出てしまいます。
## レンダリング部分について
`return()`内の`postData ? postData.sentence : ''`としている部分で、postDataに↑でとってきた記事データが格納されたら、それが表示されるようになっています。`postData.sentence`と書いていますが、`sentence`の部分はmicroCMSで定義した表示したいデータのフィールドIDが入ります。レンダリング部分は他の記事ページのレイアウトに合わせて、煮るなり焼くなりしてください！
##まとめ
サイトを見にきた人が、`/今回作ったページ`と打つとアクセスできてしまいますが、contentsIdとdraftKeyがないので何も表示されないですし、一応は問題ないと思います。

色々と改善の余地はありそうですが、とりあえずこれで投稿前の記事をプレビューで確認できるので、是非活用してみてください！