Implémentation d'une autocomplétion de documents en utilisant FlexSearch et Material-UI dans un projet React. FlexSearch gérera l'indexation rapide et la recherche, tandis que Material-UI fournira une interface épurée pour le champ de recherche et le menu déroulant des suggestions.
29 Nov 2024
Tout d'abord, installez FlexSearch et Material-UI si vous ne l'avez pas encore fait.
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled flexsearch
Créez un index FlexSearch pour les documents. Vous pouvez configurer cet index selon vos besoins, mais voici un exemple de base prenant en charge l'autocomplétion.
// utils/articleSearchIndex.ts
import leven from "leven";
import { Article } from "../components/Search";
import FlexSearch from "flexsearch";
// Créer un index FlexSearch
const index = new FlexSearch.Document({
document: {
id: "id",
index: ["title", "content"], // Champs à indexer pour la recherche
store: ["id", "title", "content"], // Champs à récupérer dans les résultats
},
language: "fr", // Support linguistique pour la tokenisation
tokenize: "forward", // Tokenisation pour l'autocomplétion
encoder: "simple", // Encodage simplifié pour la recherche
threshold: 3, // Tolérance pour la recherche approximative
resolution: 5, // Résolution plus élevée pour des résultats plus précis
});
// Ajouter des données à l'index
export const addDataToIndex = (data: Article[]) => {
data.forEach((item) => {
index.add(item);
});
};
// Fonction de recherche dans l'index
export const searchIndex = async (query: string) => {
try {
const result = await (index as any).searchAsync(query, {
index: ["title", "content"],
suggest: true, // Suggestions d'autocomplétion
pluck: "title", // On ne récupère que le titre
enrich: true, // Enrichir le format des résultats
});
return result;
} catch (error) {
console.error("Erreur lors de la tokenisation avec FlexSearch :", error);
return [];
}
};
Créons maintenant une barre de recherche en utilisant le composant Autocomplete de Material-UI. Les résultats seront récupérés dynamiquement en fonction de la saisie de l'utilisateur via FlexSearch.
// components/Search.tsx
import { useState, useEffect, ChangeEvent } from "react";
import Autocomplete from "@mui/material/Autocomplete";
import TextField from "@mui/material/TextField";
import { addDataToIndex, searchIndex } from "../utils/articleSearchIndex";
// Définir l'interface Article
export interface Article {
id: number;
title: string;
content: string;
}
// Données d'exemple pour remplir l'index
const articles: Article[] = [
{ id: 1, title: "Comment utiliser FlexSearch", content: "Un guide sur l'utilisation de FlexSearch pour la recherche de documents." },
{ id: 2, title: "Créer une autocomplétion", content: "Étapes pour implémenter l'autocomplétion avec FlexSearch." },
{ id: 3, title: "React avec FlexSearch", content: "Intégrer FlexSearch dans une application React." },
];
const Search = () => {
const [query, setQuery] = useState<string>("");
const [suggestions, setSuggestions] = useState<Article[]>([]);
// Remplir l'index FlexSearch lors du montage du composant
useEffect(() => {
addDataToIndex(articles);
}, []);
// Gérer les modifications de saisie dans la recherche
const handleSearch = (_: ChangeEvent<{}>, value: string) => {
setQuery(value);
const searchResults = searchIndex(value);
const formattedResults = searchResults.map((result) => result.doc);
setSuggestions(formattedResults);
};
return (
<Autocomplete
freeSolo
options={suggestions}
filterOptions={(x) => x} // Désactiver le filtrage côté client
getOptionLabel={(option: Article | string) =>
typeof option === "string" ? option : option.title
}
inputValue={query}
onInputChange={handleSearch}
renderInput={(params) => (
<TextField {...params} label="Rechercher des articles" variant="outlined" />
)}
/>
);
};
export default Search;
Utilisez maintenant le composant Search
dans votre fichier d'application principal pour afficher la fonctionnalité de recherche.
// App.js
import React from "react";
import Search from "./components/Search";
const App = () => {
return (
<div>
<h1>Recherche FlexSearch</h1>
<Search />
</div>
);
};
export default App;
5.1. Déclencher la recherche après un court délai (debounce)
Pour éviter trop de requêtes de recherche pendant que l'utilisateur tape, utilisez un mécanisme de debouncing. Installez lodash pour utiliser sa fonction debounce
:
npm install lodash
import { debounce } from 'lodash';
import { useCallback } from "react";
// Gérer la recherche avec un délai (debounced)
const handleDebouncedSearch = useCallback(
debounce(async (value: string) => {
const searchResults = await searchIndex(value);
setSuggestions(searchResults);
}, 500),
[]
);
const handleSearch = (_: ChangeEvent<{}>, value: string) => {
setQuery(value);
handleDebouncedSearch(value);
};
Vous pouvez ajuster dynamiquement la distance autorisée pour la correction orthographique en fonction de la longueur de la requête. Par exemple, les requêtes plus courtes auront une tolérance plus faible pour éviter les faux positifs.
import leven from "leven";
// Suggérer des corrections en utilisant la distance de Levenshtein
export const suggestIndex = (query: string, data: Article[]) => {
return data.filter((item: Article) => {
const maxDistance = item.title.length - leven(query.toLocaleLowerCase(), item.title.toLocaleLowerCase());
return maxDistance >= 6;
});
};
Si aucun résultat n'est retourné par FlexSearch, vous pouvez utiliser la correction automatique basée sur la distance de Levenshtein :
const handleDebouncedSearch = useCallback(
debounce(async (value: string) => {
let searchResults = await searchIndex(value);
if (searchResults.length === 0) {
searchResults = suggestIndex(value, articles);
} else {
searchResults = searchResults.map((r) => r.doc);
}
setSuggestions(searchResults);
}, 500),
[]
);
Index FlexSearch : Nous avons créé un index FlexSearch pour les documents, en indexant à la fois le titre et le contenu. Vous pouvez adapter cela à la structure de vos documents.
Composant Autocomplete : Le composant Autocomplete de Material-UI est utilisé pour afficher des suggestions de recherche à mesure que l'utilisateur tape.
Gestion de l'entrée de recherche : La fonction handleSearch
récupère les résultats de la recherche à partir de FlexSearch pour les afficher dans la liste déroulante.
Affichage des options : Les résultats de la recherche (documents correspondants) sont transmis au composant Autocomplete sous forme d'options. Nous utilisons getOptionLabel
pour définir ce qui sera affiché dans la liste déroulante.
Vous pouvez tester ce tutoriel directement sur CodeSandbox en suivant ce lien : FlexSearch Autocompletion.
Ou consulter le code source sur GitHub.
Tags:
Abonnez-vous à ma newsletter pour pouvoir suivre et récevoir des offres spéciales et les articles / tutos que je publie occasionnellement sur mon blog
* Vous pouvez se désabonner à tout moment en cliquant sur le lien de désabonnement contenu dans chacun de nos mails.