当サイトは、アフィリエイト広告を利用しています

algoliaのinstantsearchをカスタムする

作成日:2022月03月28日
更新日:2022年06月11日

algoliaのinstantsearchをカスタマイズする方法をメモ。
algoliaのinstantsearchは基本、下記のコンポーネントで成り立っている。

  • SearchBox
  • Hits

この二つはコンポーネントとしてalgoliakから提供されているため
そのままでも使えるがHOCを使ってカスタマイズすることもできる。
今回はカスタマイズする方法をまとめる。

パッケージのインストール

必要なパッケージをインストールする。

algoliasearch

algoliaと通信するためのパッケージ

react-instantsearch-dom

AlgoliaのライブラリのReactバージョン

bash
yarn add algoliasearch react-instantsearch-dom

実装

検索ボックスをカスタマイズしながら実装していく

InstantSearch

algoliaの検索コンポーネント。
この中に配置する

  • SearchBox
  • Hits をカスタマイズする。 algoliaの検索コンポーネント自体は下記のような形になり
    公式とほぼ同じにする
algoliaSearch.jsx
import React from 'react';
import algoliasearch from 'algoliasearch';
import { InstantSearch, Configure } from 'react-instantsearch-dom';
import SearchBox from '../searchBox'; // カスタマイズしたSearchBox
import Hits from '../hits'; // カスタマイズしたHits
// algoliaと通信するためのクライアントを作成
const algoliaClient = algoliasearch(process.env.GATSBY_ALGOLIA_APP_ID, process.env.GATSBY_ALGOLIA_SEARCH_KEY);
// 初回検索をしないために検索文字がない場合は
// dummyの結果を返すようにする処理
const searchClient = {
...algoliaClient,
search(requests) {
if (requests.every(({ params }) => !params.query)) {
return Promise.resolve({
results: requests.map(() => ({
hits: [],
nbHits: 0,
nbPages: 0,
page: 0,
processingTimeMS: 0,
})),
});
}
return algoliaClient.search(requests);
},
};
// algolia検索コンポーネント
const Search = () => {
return (
<InstantSearch searchClient={searchClient} indexName="gatsbyTechBlog">
<Configure hitsPerPage={30} />
{/* 検索ボックス */}
<SearchBox searchAsYouType={false} />
{/* 検索結果 */}
<Hits />
</InstantSearch>
);
};
export default Search;
  • hitsPerPageは1ページあたりの結果表示数
  • searchAsYouTypeはインクリメントサーチをoffにしている

SearchBox(検索ボックス)

検索ボックスコンポーネントをカスタマイズする。
HOCのconnectSearchBoxを使用することでpropsとして

  • refine
  • currentRefinement を受け取ることができるようになる 後は好きなデザインで上記の二つを使うだけ!

refine

検索クエリの更新を行うrefine関数。
引数として検索文字列を与えることでその文字列で検索を実行する。

currentRefinement

最新の検索文字列を保持している
※今回はインクリメントサーチにしないので使用しなかった

SearchBox.jsx
import { connectSearchBox } from 'react-instantsearch-dom';
import React, { useRef } from 'react';
import tw, { css } from 'twin.macro';
// connectSearchBox経由でexportするとpropsから
// refine, currentRefinementを取得できる
const SearchBox = ({ refine, currentRefinement }) => {
// input要素と紐づける
const inputVal = useRef();
// 検索を実行する関数
// enter押下かSearchボタン押下で検索するようにする
const comfirm = e => {
if (e.key === 'Enter' || e.type === 'click') {
refine(inputVal.current.value);
}
};
return (
<div
css={[
tw`flex justify-center items-center w-full p-3 space-x-2 bg-white rounded-xl shadow-lg hover:shadow-xl transform hover:scale-105 transition duration-500`,
]}
>
{/* input */}
<div css={[tw`flex bg-gray-200 p-2 w-2/6 space-x-4 rounded-lg`]}>
<svg
xmlns="http://www.w3.org/2000/svg"
css={[tw` h-6 w-6 opacity-30`]}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<input
// useRefと紐づける
ref={inputVal}
css={[
tw`outline-none bg-gray-200 w-full`,
css`
border: 0px;
`,
]}
placeholder="Article name or keyword..."
// enter押下イベントを検知する
onKeyPress={e => comfirm(e)}
/>
</div>
<button
onClick={e => comfirm(e)}
type="submit"
css={[
tw`bg-indigo-600 py-3 px-5 ml-2 text-white font-semibold rounded-lg hover:shadow-lg transition duration-300 cursor-pointer`,
css`
border: 0px;
`,
]}
>
Search
</button>
</div>
);
};
export default connectSearchBox(SearchBox);

仕様

  • 検索ボックスカーソル時にenter押下時に検索を実行する。
  • Searchボタン押下時に検索を実行する

インクリメントサーチver

一応、インクリメントサーチverも乗せる。
※インクリメントサーチの場合、input要素のonChangeイベントで検索が実行されるため
結構、リクエスト数が増える。

SearchBox.jsx
import { connectSearchBox } from 'react-instantsearch-dom';
import React, { useRef, useState } from 'react';
import tw, { css } from 'twin.macro';
const SearchBox = ({ refine, currentRefinement }) => {
return (
<div
css={[
tw`flex justify-center items-center w-full p-6 space-x-2 bg-white rounded-xl shadow-lg hover:shadow-xl transform hover:scale-105 transition duration-500`,
]}
>
{/* input */}
<div css={[tw`flex bg-gray-200 p-4 w-2/6 space-x-4 rounded-lg`]}>
<svg
xmlns="http://www.w3.org/2000/svg"
css={[tw` h-6 w-6 opacity-30`]}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
<input
value={currentRefinement}
css={[
tw`outline-none bg-gray-200 w-full`,
css`
border: 0px;
`,
]}
type="text"
placeholder="Article name or keyword..."
onChange={e => refine(e.currentTarget.value)}
/>
</div>
</div>
);
};
export default connectSearchBox(SearchBox);

inputのイベントはonChangeでないと反応しない!!

Hits(検索結果)

検索結果コンポーネントをカスタマイズする。
HOCのconnectHitsを使用することでpropsとして

  • hits

を受け取ることができるようになる

hits

hitは検索結果オブジェクトリストなので、mapなどで加工しながら
好きなように表示させることができる

hits.jsx
import React from 'react';
import { connectHits, Snippet, Highlight } from 'react-instantsearch-dom';
import { Link } from 'gatsby';
import tw, { css } from 'twin.macro';
const Hits = ({ hits }) => {
// 表示用のコンポーネントを使う
return <Cards hits={hits} />;
};
// connectHits経由でexportするとpropsから
// hitsを取得できる
const Cards = ({ hits }) => {
return (
<>
{hits &&
hits.map(hit => {
return (
<div key={hit.objectID} css={[tw`mx-auto my-3 sm:px-6 lg:px-8 w-5/6`]}>
<div css={[tw`overflow-hidden shadow-md`]}>
<div
css={[
tw`px-6 py-4 bg-white font-bold`,
css`
border-bottom: 1px solid #e5e7eb;
`,
]}
>
<Link to={`/${hit.slug}`} activeClassName="active">
{/* 検索結果から検索文字をハイライト */}
<Highlight hit={hit} attribute="title" tagName="mark" />
</Link>
</div>
<div css={[tw`p-3 bg-white max-h-48 break-words`]}>
{/* 検索結果(切り取り結果)から検索文字をハイライト */}
<Snippet hit={hit} attribute="content" tagName="mark" />
</div>
</div>
</div>
);
})}
</>
);
};
// HOC関数でexport
export default connectHits(Hits);

HighlightやSnippetのコンポーネントにもHOC関数があるので
カスタマイズすることができる。
※今回は得にカスタマイズしない。詳しくは公式 を参照

まとめ

検索ボックスを構成するコンポーネントはぼぼalgoliaでHOC関数が用意されているので
HOCを使えば自由にカスタマイズできる。
SearchBoxやHits以外にもStatusやPaginationなどのコンポーネントがあるので
好きなものを組み合わせて検索ページを作ることができる。

参考

Gatsby+microCMSサイトにAlgolia全文検索機能を実装
Algolia InstantSearchのカスタムUIをReact+typescript+Material-UIで作成する
Gatsbyでalgolia検索を導入する
React InstantSearch

新着記事

タグ別一覧
top