当サイトは、アフィリエイト広告を利用しています
algoliaのinstantsearchをカスタマイズする方法をメモ。
algoliaのinstantsearchは基本、下記のコンポーネントで成り立っている。
この二つはコンポーネントとしてalgoliakから提供されているため
そのままでも使えるがHOCを使ってカスタマイズすることもできる。
今回はカスタマイズする方法をまとめる。
必要なパッケージをインストールする。
algoliaと通信するためのパッケージ
AlgoliaのライブラリのReactバージョン
yarn add algoliasearch react-instantsearch-dom
検索ボックスをカスタマイズしながら実装していく
algoliaの検索コンポーネント。
この中に配置する
import React from 'react';import algoliasearch from 'algoliasearch';import { InstantSearch, Configure } from 'react-instantsearch-dom';import SearchBox from '../searchBox'; // カスタマイズしたSearchBoximport 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;
検索ボックスコンポーネントをカスタマイズする。
HOCのconnectSearchBoxを使用することでpropsとして
検索クエリの更新を行うrefine関数。
引数として検索文字列を与えることでその文字列で検索を実行する。
最新の検索文字列を保持している
※今回はインクリメントサーチにしないので使用しなかった
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 (<divcss={[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`]}><svgxmlns="http://www.w3.org/2000/svg"css={[tw` h-6 w-6 opacity-30`]}fill="none"viewBox="0 0 24 24"stroke="currentColor"><pathstrokeLinecap="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><buttononClick={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);
一応、インクリメントサーチverも乗せる。
※インクリメントサーチの場合、input要素のonChangeイベントで検索が実行されるため
結構、リクエスト数が増える。
import { connectSearchBox } from 'react-instantsearch-dom';import React, { useRef, useState } from 'react';import tw, { css } from 'twin.macro';const SearchBox = ({ refine, currentRefinement }) => {return (<divcss={[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`]}><svgxmlns="http://www.w3.org/2000/svg"css={[tw` h-6 w-6 opacity-30`]}fill="none"viewBox="0 0 24 24"stroke="currentColor"><pathstrokeLinecap="round"strokeLinejoin="round"strokeWidth="2"d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg><inputvalue={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でないと反応しない!!
検索結果コンポーネントをカスタマイズする。
HOCのconnectHitsを使用することでpropsとして
を受け取ることができるようになる
hitは検索結果オブジェクトリストなので、mapなどで加工しながら
好きなように表示させることができる
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`]}><divcss={[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関数でexportexport 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