🌊

microCMSのサンプルコードからNext.jsを学ぶの巻

2024/12/27に公開

こんにちは、Spacemarketのフロントエンドエンジニアの8zkです。
前回はmicroCMSの導入について触れましたが、肝心なNext.jsのtemplateのコードについては全く触れていなかったので、それについて学びつつアウトプットしたいと思い、ブログを書いています。

使用ライブラリ

ではさっそくですが シンプルなブログ で使われているライブラリがこちらです。

"dependencies": {
    "@types/cheerio": "^0.22.31",
    "@types/node": "18.15.3",
    "@types/react": "18.0.28",
    "@types/react-dom": "18.0.11",
    "cheerio": "^1.0.0-rc.12",
    "date-fns": "^2.29.3",
    "date-fns-tz": "^2.0.0",
    "encoding": "^0.1.13",
    "eslint": "8.36.0",
    "eslint-config-next": "13.2.4",
    "eslint-config-prettier": "^8.7.0",
    "highlight.js": "^11.7.0",
    "microcms-js-sdk": "^2.3.2",
    "next": "^13.4.4",
    "prettier": "^2.8.4",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "typescript": "4.9.5"
}

この中で特に注目すべきライブラリは microcms-js-sdk です。
これはmicroCMSのAPIをcallするためのclientや型定義が含まれており、これなしにmicroCMSを使うのは中々難しいと思います。

microcms-js-sdkの使い方

コードの中ではこのように使われています。

import { createClient } from 'microcms-js-sdk';
import type {
  MicroCMSQueries,
  MicroCMSImage,
  MicroCMSDate,
  MicroCMSContentId,
} from 'microcms-js-sdk';
import { notFound } from 'next/navigation';

...

export type Blog = {
  title: string;
  description: string;
  content: string;
  thumbnail?: MicroCMSImage;
  tags?: Tag[];
  writer?: Writer;
};

...

// Initialize Client SDK.
export const client = createClient({
  serviceDomain: process.env.MICROCMS_SERVICE_DOMAIN,
  apiKey: process.env.MICROCMS_API_KEY,
});

// ブログ一覧を取得
export const getList = async (queries?: MicroCMSQueries) => {
  const listData = await client
    .getList<Blog>({
      endpoint: 'blog',
      queries,
    })
    .catch(notFound);
  return listData;
};

// ブログの詳細を取得
export const getDetail = async (contentId: string, queries?: MicroCMSQueries) => {
  const detailData = await client
    .getListDetail<Blog>({
      endpoint: 'blog',
      contentId,
      queries,
    })
    .catch(notFound);

  return detailData;
};

基本的には createClient を使ってclientを作成し、それをwrapした関数を作るイメージです。
getList は引数に queries?: MicroCMSQueries を取ります。
これは一般的なoptionである limitoffset などを設定することができます。
そのため引数次第で様々なデータを取得することが可能になります。

また client には複数のデータを取得する client.getList と単一のデータを取得する client.getListDetailがあります。
これらのメソッドの引数に endpoint を指定し、対象となるリソースを確定させます。

また client.getListDetail に限り contentId を指定することで対象となるcontentを取得します。

microCMSのAPIをcallしてみた(getList編)

では実際にmicroCMSのAPIをcallしているコードを見てみましょう。

// app/page.tsx
import { getList } from '@/libs/microcms';
import { LIMIT } from '@/constants';
import Pagination from '@/components/Pagination';
import ArticleList from '@/components/ArticleList';

export const revalidate = 60;

export default async function Page() {
  const data = await getList({
    limit: LIMIT,
  });
  return (
    <>
      <ArticleList articles={data.contents} />
      <Pagination totalCount={data.totalCount} />
    </>
  );
}

こちらのファイルはNext.jsの app ディレクトリ直下の page.tsx です。
そして use client を使用していないのでRSC(React Server Components)として扱われます。
なのでこのコンポーネントはserver側で getList をcallすることになります。

data.contents が実際のdataの実体です。
data.totalCount は取得できた data.contents のlengthではなく、全てのデータの数を表しているため、Paginationを作る時にとても便利です。

microCMSのAPIをcallしてみた(getListDetail編)

こちらのファイルは先ほどとは違い、app/articles/[slug]/page.tsx です。

...
import { getDetail } from '@/libs/microcms';
import Article from '@/components/Article';

type Props = {
  params: {
    slug: string;
  };
  searchParams: {
    dk: string;
  };
};

...

export default async function Page({ params, searchParams }: Props) {
  const data = await getDetail(params.slug, {
    draftKey: searchParams.dk,
  });

  return <Article data={data} />;
}

microCMSではドラフト機能があります。
この機能は名前の通り、下書き機能です。

現状の画面がこちらとなります。(URL: http://localhost:3000/articles/{slug}

管理画面からこの投稿を確認します。

この投稿を以下のように変更し、 公開 の代わりに 下書きを追加 をclickします。

元のURLではUIに特に変化はありません。
しかし下書きにしたことによってdraftKeyが生成されたので、http://localhost:3000/articles/{slug}?dk={draftKey} にアクセスすると・・・

ちゃんと下書き状態の画面が確認できます。
この機能のすごいところは投稿後でも下書きを追加でき、それらを別のURLで管理しているところです。とても良い!

コード的には getDetaildraftKey: searchParams.dk, を渡すだけですね!

検索機能 on microCMS

このサイトには検索機能があります。
UIとしては以下になります。

こちらに検索文字列を入力し、Enterを押すと http://localhost:3000/search?q={keyword} なURLに遷移します。
そして検索結果に応じた投稿が取得できます。

コードは以下になります。

import { getList } from '@/libs/microcms';
import ArticleList from '@/components/ArticleList';
import Pagination from '@/components/Pagination';

type Props = {
  searchParams: {
    q?: string;
  };
};

export const revalidate = 60;

export default async function Page({ searchParams }: Props) {
  const data = await getList({
    q: searchParams.q,
  });

  return (
    <>
      <ArticleList articles={data.contents} />
      <Pagination totalCount={data.totalCount} basePath="/search" q={searchParams.q} />
    </>
  );
}

getList には q というパラメーターがあり、ここに searchParams.q を渡すことで検索機能を実装しています。
このように getListgetListDetail には様々なoptionがあるので、データ取得をより便利にさせています。

感想

個人的には普段テンプレートの中身を見ることなんて殆どありませんが、たまに見てみると結構勉強になったのでよかったです。
またブログサービスはログイン情報と紐づかないことが多いのでRSCとは相性が良いなと感じました。

さいごに

スペースマーケットでは、一緒にサービスを成長させていく仲間を探しています。
話を聞いてみたい、ちょっとだけ興味がある、などでも大歓迎です!
ご興味ありましたら是非ご連絡ください!

スペースマーケット Engineer Blog

Discussion