AlgoliaのInstantsearch.js(React)を使った検索機能を、力技で特定ユーザーのみに提供する
この記事はAlgolia Advent Calendar2021、5日目の記事です。 やりたかったこと(背景) 自分のサイトに、プレミアム機能的なものをつけてみたかった プレミアム限定にできそうな機能で、やる気が出そうな […]
目次
この記事はAlgolia Advent Calendar2021、5日目の記事です。
やりたかったこと(背景)
- 自分のサイトに、プレミアム機能的なものをつけてみたかった
- プレミアム限定にできそうな機能で、やる気が出そうなものが思い浮かばなかった
- 「すでにAlgoliaいれてるし、これでなにかするか」
やったこと
1、公式のサンプルを漁って土台を見つける
公式のドキュメントにある「未入力時に検索を実行しない」コードサンプルをベースにしました。
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom';
const algoliaClient = algoliasearch(
'undefined',
'undefined'
);
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);
},
};
const App = () => (
<InstantSearch searchClient={searchClient} indexName="instant_search">
<SearchBox />
<Hits />
</InstantSearch>
);
ポイントは、「InstantSearch
に渡すsearchClient
オブジェクトの、search
の挙動を上書きすること」です。
サンプルコードは、「検索クエリがない場合、空の結果を返す」挙動をif文で表現しています。
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,
})),
});
}
...
つまり、ここの上書き条件をカスタムすれば、「ログインユーザーのみ動作する」などの挙動が実現できます。
2、React hookでクライアントの更新処理をいれる
アクセスするユーザーの状態によって挙動が変わるため、searchClient
はReact Component内で定義する必要があります。そのためuseMemo
などを使う形に実装を変更します。
const noResult = {
hits: [],
nbHits: 0,
nbPages: 0,
page: 0,
processingTimeMS: 0,
};
export const AlgoliaSearchProvider = ({ children, hasSubscription }) => {
const searchClient = useMemo(() => {
if (!hasSubscription) {
/**
* 無課金ユーザーは動かさない
*/
return {
search(requests) {
return Promise.resolve({
results: requests.map(() => noResult),
});
},
};
}
/**
* 課金ユーザーはAlgolia
*/
return {
search(requests, requestOptions) {
if (requests.every(({ params }) => !params || !params.query)) {
return Promise.resolve({
results: requests.map(() => ({
hits: [],
nbHits: 0,
nbPages: 0,
page: 0,
processingTimeMS: 0,
})),
});
}
return algoliaClient.search(requests, requestOptions);
},
};
}, [hasSubscription]);
return (
<InstantSearch indexName="wp_posts_post" searchClient={searchClient}>
<Configure clickAnalytics />
{children}
</InstantSearch>
);
};
かなりの力技ですが、これでユーザーの状態が変わると、search
の挙動も変わります。
これでログイン中ユーザーや課金ユーザーなど限定でAlgoliaを使った検索機能を提供できるようになりました。
ちなみに、かなり力技なので、いろいろ細かく設定をしたい場合や、Recommendなどを使いたい場合には、本当に動くか検証してから採用するようにしてください。
おまけ:検索クライアントを差し替えたい場合
「ただ検索させなくなるのは嫌だ」という場合、search
メソッド内で以下のようなコードを入れると、検索クエリを取得できます。
const searchWord = requests
.map(({ params }) => {
if (!params || !params.query) return null;
return params.query;
})
.join(" ");
あとはこれをAlgolia以外の検索APIに投げれば、たとえば「無料ユーザーはWP APIでお手軽に、課金してくれた人はAlgoliaで高機能検索体験を」みたいなこともできる(はず)です。