作成日: 2023-4-25
更新日: 2023-9-28
Fuse.jsは、軽量で高速なJavaScriptライブラリであり、クライアントサイドでのあいまい検索(ファジー検索)を実現します。
あいまい検索とは、検索クエリが完全に一致しなくても、類似した結果を返すことができる検索方法です。
Fuse.jsは、スペルミスや部分的な一致に寛容であることが特徴であり、検索の精度や柔軟性を向上させます。
このライブラリは、JSONデータの配列を対象とした検索を行い、検索クエリとデータの類似度に基づいて結果を返します。
現状(2023/4/14)のGitHubのスター数は15,700であり、その他のライブラリと比べても非常に人気があります。
まずはFuse.jsに対して、検索データを引数として渡して、インスタンス化します。
インスタンス化する際に引数は2個指定することができます。
第1引数は、検索をする対象データを指定できます。
第2引数は、検索時の詳細設定を指定できます。
例えば、keyオプションに検索時に使いたいデータのキーを指定することができます。
指定する場合は、配列内に文字列で指定します。
カンマ区切りすれば複数指定することができます。
new Fuse(searchTargetList, {
key: ["title", "content"],
})
他にもオプションが複数ありますが、代表的なものを3個紹介します。
今回実装するNext.jsでの検索機能の実装はブログ記事の検索機能を想定しています。
まずSSG等でAPIから取得したブログ記事のデータを使ってFuse.jsのインスタンス化を行います。
後はインスタンスにキーワードを渡せば、該当するデータを戻り値として返してくれます。
$ npm install --save fuse.js
まずはデータとオプションを指定して、Fuse.jsをインスタンス化します。
今回は、SSGで取得したデータを使います。
import { GetStaticProps, NextPage } from 'next';
import Fuse from 'fuse.js';
type blogResponse = {
contents: Array<{
title: string,
content: string
}>
}
type SSGResponse = {
response: blogResponse
}
export const getStaticProps: GetStaticProps<SSGResponse> = async (context) => {
const response: blogResponse = await fetcher('一覧取得のAPIエンドポイントを指定')
return {
props: {
response
}
}
}
const Home: NextPage<SSGResponse> = (props) => {
const { response } = props;
// useMemoでFuseインスタンスをキャッシュする
const fuseInstance = useMemo(() => {
const fuse = new Fuse(response.contents, {
keys: ["title", "content"],
threshold: 0.3,
})
return fuse
}, [response])
return (
<>
</>
)
}
SSGはビルド時にしかデータ取得を行わないので、useMemoでキャッシュしておけば、クライアントサイドではインスタンス化の関数を実行する必要がなくなります。
注意点としては、記事の更新等によりデータが更新された場合は対応ができません。
Ondemand ISRやISRを設定することで上記に対応することができます。
input要素に入力されたキーワードを取得して検索結果を取得します。
import { GetStaticProps, NextPage } from 'next';
import { useCallback, useMemo } from 'react';
import Fuse from 'fuse.js';
type blogResponse = {
contents: Array<{
title: string,
content: string
}>
}
type SSGResponse = {
response: blogResponse
}
export const getStaticProps: GetStaticProps<SSGResponse> = async (context) => {
const response: blogResponse = await fetcher('一覧取得のAPIエンドポイントを指定')
return {
props: {
response
}
}
}
const Home: NextPage<SSGResponse> = (props) => {
const { response } = props;
// useMemoでFuseインスタンスをキャッシュする
const fuseInstance = useMemo(() => {
const fuse = new Fuse(response.contents, {
keys: ["title", "content"],
threshold: 0.3,
})
return fuse
}, [response])
const inputValue = React.useRef<HTMLInputElement>(null);
const handleSubmit = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
// ここで検索処理を行う
const value = inputValue.current? inputValue.current.value : '';
const results = fuseInstance.search(value)
console.log(results)
if (inputValue.current) {
inputValue.current.value = '';
}
}
}, [fuseInstance])
return (
<>
<input
type='text'
ref={inputValue}
onKeyDown={handleSubmit}
placeholder='検索キーワード'
/>
</>
)
}
console.log上に検索結果が表示されると思います。
Next.jsで検索機能を実現する場合、色々な方法があります。
今回はJavaScriptのライブラリであるFuse.jsで実装しました。
Next.jsはデータの取得方法がSSG以外にもSSRがあったりしますので、そちらのデータを使うこともできます。
SSRの概要については以下の記事を参考にしてください。