🔍

Next.js × microCMSで作成したブログに検索機能の実装

2021/12/16に公開

はじめに

ブログに検索機能を実装してみました。
下画像のような感じです。

実行環境

  • Next.js
  • TypeScript
  • Recoil
  • TailwindCSS

Stateの用意

Recoilでinputのvalue値を管理するStateを定義

searchValue.tsx
import { atom } from "recoil";

export const searchValue = atom<string>({
  key: "searchValue",
  default: ""
})

検索フィールドの作成

検索画面を作成

SearchField.tsx
export const SearchField:VFC = () => {
    const [value, setValue] = useRecoilState(searchValue);
    const router = useRouter();

    const onChangeValue = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
      setValue(e.target.value);
    },[]);

    const handleClickSubmitButton = useCallback(
      (e: React.MouseEvent<HTMLButtonElement>) => {
        e.preventDefault();
        router.push(`/search/?keyword=${value}`);
      },
      [value, router]
    );

    const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        router.push(`/search/?keyword=${value}`)
      }
    }, [value,router]);

    return (
      <form className="flex flex-col items-center space-y-2 mb-3 surface:flex-row surface:justify-center surface:space-y-0 surface:space-x-2">
        <SearchInput value={value} onChange={onChangeValue} onKeyDown={handleKeyDown}/>
        <SubmitButton onClick={handleClickSubmitButton} />
      </form>
    );
}

上記で行っていることは
Recoilで定義したStateを呼ぶ

const [value, setValue] = useRecoilState(searchValue);

onChangeValue:inputのvalue値をStateに挿入
handleClickSubmitButtonhandleKeyDown:value値をURLパラメータに入れて画面遷移

API RoutesのAPIを叩く処理

API key漏洩防止のために、API Routes側でmicroCMSのAPIを叩き、SearchコンポーネントはAPI Routesで定義したAPIエンドポイントを叩くようにします。

Search.tsx
const fetcher = (url: string, value: string): Promise<ApiTypes> => {
  return fetch(`${url}?keyword=${value}`)
    .then((res) => res.json() );
};

export const Search: VFC = () => {
  const router = useRouter();

  // apiから検索結果の受け取り
  const { data,error } = useSWR<ApiTypes,Error>(["api/search",router.query.keyword],fetcher);

  if (error) return <div>failed to load</div>
  if (!data) return (
    <>
      <Header />
      <Spinner />
      <Footer/>
    </>
  )
    return (
    <>
      <Head>
        <title>{router.query.keyword}」の検索結果</title>
        <link rel="icon" href="/images/android-chrome-36x36.png" />
      </Head>
      <Header />
      <SearchField />
      <h1 className="text-center font-bold text-2xl my-4">{router.query.keyword} の検索結果</h1>
      <div className="mb-6 px-5 md:flex md:items-start">
        <Blog blogData={data} />
        <SideMenu />
      </div>
      <Footer />
    </>
  );
 }

今回はAPI RoutesのエンドポイントをuseSWRで叩いています。

dataの取得中はSpinnerを表示し、dataが無事に取得出来たらBlogコンポーネントに渡して、検索して取得できたブログ一覧を表示するようにしています。

microCMSのAPIを叩くAPI Routesの実装

URLパラメータを取得して、microCMSのAPIを叩くようにしています。

api/search.ts
const getSearchBlogs = async ( req: NextApiRequest, res: NextApiResponse ) => {
  const { keyword } = req.query as { keyword: string };
  const searchBlogs = await fetch(
    `https://lotteblog.microcms.io/api/v1/myblog?q=${encodeURI(keyword)}`,
    key
  )
    .then((res) => res.json())
    .catch(() => null);

  return res.status(200).json(searchBlogs);
};

export default getSearchBlogs;

qを付けることでmicroCMSでは全文検索が出来るようです。

コンテンツAPIにて全文検索ができるようになりました!
q パラメータをリクエスト時に付けるだけという非常にシンプルな形でご利用いただけます。

encodeURI:URLで使用できない文字を%エンコーディングという方式でエンコード

  const searchBlogs = await fetch(
    `https://lotteblog.microcms.io/api/v1/myblog?q=${encodeURI(keyword)}`,
    key
  )

さいごに

Next.js × microCMSで検索機能を実装しました。
なにか間違いなどある場合はご指摘していただけるとありがたいです。

参考

https://ji23-dev.com/blogs/microcms-full-text-search

Discussion