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にクエリ文字列が渡ってくるがクエリ文字列が空の場合はダミー用のレスポンスを返すようにしている
これを応用すれば他のパターンでもリクエスト送る前に独自の処理を差し込むことも可能である