Faster search with minisearch

This commit is contained in:
Tyler Hallada 2022-01-25 00:52:52 -05:00
parent 8d3b801aab
commit 716900a397
3 changed files with 25 additions and 22 deletions

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import type mapboxgl from "mapbox-gl"; import type mapboxgl from "mapbox-gl";
import Fuse from "fuse.js"; import MiniSearch, { SearchResult } from "minisearch";
import useSWRImmutable from "swr/immutable"; import useSWRImmutable from "swr/immutable";
import styles from "../styles/SearchBar.module.css"; import styles from "../styles/SearchBar.module.css";
@ -17,11 +17,6 @@ interface Mod {
id: number; id: number;
} }
interface SearchResult {
item: Mod;
refIndex: number;
}
const jsonFetcher = async (url: string): Promise<Mod | null> => { const jsonFetcher = async (url: string): Promise<Mod | null> => {
const res = await fetch(url); const res = await fetch(url);
@ -38,9 +33,9 @@ const jsonFetcher = async (url: string): Promise<Mod | null> => {
const SearchBar: React.FC<Props> = ({ clearSelectedCell, map }) => { const SearchBar: React.FC<Props> = ({ clearSelectedCell, map }) => {
const router = useRouter(); const router = useRouter();
const fuse = useRef<Fuse<Mod> | null>(null) as React.MutableRefObject< const searchEngine = useRef<MiniSearch<Mod> | null>(
Fuse<Mod> null
>; ) as React.MutableRefObject<MiniSearch<Mod>>;
const { data, error } = useSWRImmutable( const { data, error } = useSWRImmutable(
`https://mods.modmapper.com/mod_search_index.json`, `https://mods.modmapper.com/mod_search_index.json`,
@ -48,8 +43,16 @@ const SearchBar: React.FC<Props> = ({ clearSelectedCell, map }) => {
); );
useEffect(() => { useEffect(() => {
if (data && !fuse.current) { if (data && !searchEngine.current) {
fuse.current = new Fuse(data as unknown as Mod[], { keys: ["name"] }); searchEngine.current = new MiniSearch({
fields: ["name"],
storeFields: ["name", "id"],
searchOptions: {
fields: ["name"],
fuzzy: 0.2,
},
});
searchEngine.current.addAll(data as unknown as Mod[]);
} }
}, [data]); }, [data]);
@ -77,8 +80,8 @@ const SearchBar: React.FC<Props> = ({ clearSelectedCell, map }) => {
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearch(e.target.value); setSearch(e.target.value);
if (fuse.current) { if (searchEngine.current) {
const results: { item: Mod; refIndex: number }[] = fuse.current.search( const results: SearchResult[] = searchEngine.current.search(
e.target.value e.target.value
); );
setResults(results); setResults(results);
@ -122,12 +125,12 @@ const SearchBar: React.FC<Props> = ({ clearSelectedCell, map }) => {
<ul className={styles["search-results"]}> <ul className={styles["search-results"]}>
{results.map((result) => ( {results.map((result) => (
<li <li
key={result.item.id} key={result.id}
onClick={onChooseResult(result.item)} onClick={onChooseResult({ id: result.id, name: result.name })}
onTouchStart={() => setClickingResult(true)} onTouchStart={() => setClickingResult(true)}
onMouseDown={() => setClickingResult(true)} onMouseDown={() => setClickingResult(true)}
> >
{result.item.name} {result.name}
</li> </li>
))} ))}
</ul> </ul>

10
package-lock.json generated
View File

@ -1210,11 +1210,6 @@
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true "dev": true
}, },
"fuse.js": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.5.3.tgz",
"integrity": "sha512-sA5etGE7yD/pOqivZRBvUBd/NaL2sjAu6QuSaFoe1H2BrJSkH/T/UXAJ8CdXdw7DvY3Hs8CXKYkDWX7RiP5KOg=="
},
"geojson-vt": { "geojson-vt": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
@ -1716,6 +1711,11 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}, },
"minisearch": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/minisearch/-/minisearch-3.2.0.tgz",
"integrity": "sha512-Nq3o/a9mhvokHXKCS9zxAd0t1z/eSjdtmvfBfvGI2D0/Fx8xUjrOdpjqbU7DXRyH8obowhELR1+L+i3TV7Y21g=="
},
"ms": { "ms": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",

View File

@ -11,9 +11,9 @@
"@types/javascript-color-gradient": "^1.3.0", "@types/javascript-color-gradient": "^1.3.0",
"@types/mapbox-gl": "^2.6.0", "@types/mapbox-gl": "^2.6.0",
"date-fns": "^2.28.0", "date-fns": "^2.28.0",
"fuse.js": "^6.5.3",
"javascript-color-gradient": "^1.3.2", "javascript-color-gradient": "^1.3.2",
"mapbox-gl": "^2.6.1", "mapbox-gl": "^2.6.1",
"minisearch": "^3.2.0",
"next": "12.0.8", "next": "12.0.8",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",