AlgoliaのInstantsearchを用いて検索UIを作っていたがページ読み込み時に空のリクエストが発生するらしくリクエストを消費させたくないと思ったので調べて対応してみた
Algoliaの料金体系
自分はFreeプランしか使っていないが
10000req/月
もしくは10000Record/月
までは無料で使える
ページ読み込み時にクエリが走る状態だと無駄にRequestを消費してしまう
たとえばPVが増えれば増えるほどリクエストが送られる状態になってしまう
まぁそんなにPVあるかと言われると微妙だが対応できるなら対応するにこしたことはない
Instantsearch
Algoliaが提供する検索UIを構築するためのライブラリ
基本的にAlgoliaを使うのであればUI側はInstantsearchを使って開発することになるはず
さまざまなコンポーネントが最初から用意されているので凝った使い方をしないならさっと検索UIを作成できる
そしてさらにReact、Angular、Vueなどそれぞれに対応できるよう別々にライブラリを提供している
Reactについては2種類あり、旧版のreact-instantsearch-dom
、新版のreact-instantsearch-hooks-web
がある
react-instantsearch-hooks-web
の方は、名前の通りReact Hooksが使えるようになっている
React Instantsearch(旧)のドキュメントを見に行くと「新たに使う場合はhooks版を使ってください」と書いてあったので基本的にはhooksの方を使えば良さそう
今回はアナウンスに従いReact Instantsearch Hooks
を使った
公式ドキュメント
Conditional requests with React InstantSearch Hooks | Algolia
https://www.algolia.com/doc/guides/building-search-ui/going-further/conditional-requests/react-hooks/www.algolia.com
前置きが長くなったが、掲題を実現するための方法は公式ドキュメントに載っている
英語だがかなり丁寧に解説してくれている
空のクエリを検知して空の場合のみダミーのレスポンスを返すようにsearchClient
をラップする
例だとJavaScriptなのでTypeScriptの実装例として(型注釈入れただけ)残しておく
tsx(一部抜粋)
ペライチのページでコードを書いてみた
InfiniteHits
のコンポーネントは今回の話の対象ではないので割愛している
import type { NextPage } from "next"; import { MultipleQueriesResponse, MultipleQueriesQuery, } from "@algolia/client-search"; import algoliasearch from "algoliasearch/lite"; import { InstantSearch, SearchBox, Index, PoweredBy, InfiniteHits, } from "react-instantsearch-hooks-web"; import type { SearchClient } from "instantsearch.js"; const Search: NextPage = () => { const indices = (process.env.NEXT_PUBLIC_ALGOLIA_INDICES || "").split(","); const algoliaClient = algoliasearch( process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "", process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY || "" ); const searchClient: SearchClient = { ...algoliaClient, search: <SearchResponse,>(requests: Readonly<MultipleQueriesQuery[]>) => { if (requests.every(({ params }) => !params?.query)) { return Promise.resolve<MultipleQueriesResponse<SearchResponse>>({ results: requests.map(() => ({ hits: [], nbHits: 0, nbPages: 0, page: 0, processingTimeMS: 0, hitsPerPage: 0, exhaustiveNbHits: true, query: "", params: "", })), }); } return algoliaClient.search(requests); }, }; return ( <InstantSearch searchClient={searchClient} indexName={indices[0]}> <SearchBox placeholder="Search"></SearchBox> {indices.map((index) => { return ( <div key={index}> <Index key={index} indexName={index}> <h2>{index}</h2> <InfiniteHits hitComponent={PageHit} ></InfiniteHits> </Index> </div> ); })} <PoweredBy /> </InstantSearch> ); }; export default Search;
searchClient生成時にsearch
プロパティだけ別の処理を差し込んでいる
params.query
にクエリ文字列が渡ってくるがクエリ文字列が空の場合はダミー用のレスポンスを返すようにしている
これを応用すれば他のパターンでもリクエスト送る前に独自の処理を差し込むことも可能である