Comment améliorer les performances de recherche dans React With Anti-Rebond
Dans le cadre de la conception d'une fonctionnalité de recherche avec React, l'événement `onChange` déclenche la fonction de recherche à chaque caractère saisi par l'utilisateur dans le champ de texte. Cette approche peut engendrer des difficultés en termes de performances, surtout si des appels d'API ou des requêtes en base de données sont effectués. Les sollicitations répétées de la fonction de recherche peuvent surcharger le serveur, entraînant des dysfonctionnements ou une interface utilisateur peu réactive. C'est là que l'anti-rebond entre en jeu pour pallier ce problème.
Qu'est-ce que l'anti-rebond ?
Habituellement, la fonctionnalité de recherche dans React est mise en œuvre en invoquant une fonction de gestion d'événement `onChange` à chaque frappe, comme illustré ci-dessous :
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Recherche de:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Rechercher ici..."
/>
);
}
Bien que cette méthode fonctionne, l'appel au serveur pour actualiser les résultats de recherche à chaque saisie peut s'avérer coûteux. Par exemple, pour la recherche de "webdev", l'application enverra une requête au serveur avec les valeurs "w", "we", "web", et ainsi de suite.
L'anti-rebond est une technique qui consiste à différer l'exécution d'une fonction jusqu'à ce qu'un laps de temps spécifique se soit écoulé. La fonction d'anti-rebond surveille chaque saisie de l'utilisateur et empêche l'appel au gestionnaire de recherche jusqu'à l'expiration du délai. Si l'utilisateur continue de taper pendant ce délai, le minuteur est réinitialisé et React invoque à nouveau la fonction pour un nouveau délai. Ce processus se répète tant que l'utilisateur continue de saisir du texte.
En attendant que les utilisateurs cessent de taper, l'anti-rebond s'assure que votre application n'effectue que les requêtes de recherche strictement nécessaires, ce qui réduit la charge du serveur.
Comment mettre en œuvre l'anti-rebond dans une recherche React ?
Plusieurs bibliothèques sont disponibles pour l'implémentation de l'anti-rebond. Il est également possible de le réaliser manuellement en utilisant les fonctions `setTimeout` et `clearTimeout` de JavaScript.
Cet article utilise la fonction d'anti-rebond de la bibliothèque lodash.
En supposant que vous ayez déjà un projet React opérationnel, créez un nouveau composant nommé "Search". Si ce n'est pas le cas, vous pouvez créer une application React à l'aide de l'utilitaire `create-react-app`.
Dans le fichier du composant "Search", copiez le code ci-dessous pour créer un champ de recherche qui déclenche une fonction de gestion à chaque frappe :
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Recherche de:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Rechercher ici..."
/>
);
}
Pour implémenter l'anti-rebond sur la fonction `handleSearch`, transmettez-la à la fonction d'anti-rebond de lodash.
import debounce from "lodash.debounce";
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Recherche de:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 1000);
const handleChange = (e) => {
setSearchTerm(e.target.value);
debouncedSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Rechercher ici..."
/>
);
}
Dans la fonction d'anti-rebond, vous passez la fonction que vous souhaitez retarder (ici, `handleSearch`) et le délai en millisecondes (ici, 500 ms).
Cependant, le code ci-dessus, bien qu'il soit conçu pour différer l'appel à la requête `handleSearch` jusqu'à l'arrêt de la saisie par l'utilisateur, ne fonctionnera pas correctement dans React. Nous allons expliquer pourquoi dans la section suivante.
Anti-rebond et ré-affichages
Cette application utilise une entrée contrôlée. Cela signifie que la valeur de l'état contrôle la valeur de l'entrée ; chaque fois qu'un utilisateur tape dans le champ de recherche, React actualise l'état.
Dans React, lors d'une modification d'une valeur d'état, React ré-affiche le composant et exécute toutes les fonctions qu'il contient.
Dans le composant "Search" ci-dessus, lorsque le composant est ré-affiché, React exécute la fonction d'anti-rebond. Cette dernière crée un nouveau minuteur qui suit le délai, tandis que l'ancien minuteur reste en mémoire. Lorsque son délai est écoulé, il déclenche la fonction de recherche. Cela signifie que la fonction de recherche n'est jamais soumise à l'anti-rebond, mais seulement retardée de 500 ms. Ce cycle se répète à chaque ré-affichage : une nouvelle minuterie est créée, l'ancienne arrive à expiration et appelle la fonction de recherche.
Pour que l'anti-rebond fonctionne correctement, elle ne doit être appelée qu'une seule fois. Pour ce faire, vous pouvez appeler la fonction d'anti-rebond en dehors du composant ou utiliser la technique de mémorisation. De cette façon, même si le composant est ré-affiché, React ne l'exécutera pas de nouveau.
Définition de la fonction d'anti-rebond en dehors du composant "Search"
Déplacez la fonction d'anti-rebond en dehors du composant "Search" comme suit :
import debounce from "lodash.debounce"
const handleSearch = (searchTerm) => {
console.log("Recherche de:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 500);
Maintenant, dans le composant "Search", appelez `debouncedSearch` et transmettez le terme de recherche.
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleChange = (e) => {
setSearchTerm(e.target.value);
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Rechercher ici..."
/>
);
}
La fonction de recherche ne sera appelée qu'une fois le délai écoulé.
Mémorisation de la fonction d'anti-rebond
La mémorisation consiste à mettre en cache les résultats d'une fonction et à les réutiliser lorsque la fonction est appelée avec les mêmes arguments.
Pour mémoriser la fonction d'anti-rebond, utilisez le hook `useMemo`.
import debounce from "lodash.debounce";
import { useCallback, useMemo, useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = useCallback((searchTerm) => {
console.log("Recherche de:", searchTerm);
}, []);
const debouncedSearch = useMemo(() => {
return debounce(handleSearch, 500);
}, [handleSearch]);
const handleChange = (e) => {
setSearchTerm(e.target.value);
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Rechercher ici..."
/>
);
}
Notez que la fonction `handleSearch` a également été encapsulée dans un hook `useCallback` pour s'assurer que React ne l'appelle qu'une seule fois. Sans le hook `useCallback`, React exécuterait la fonction `handleSearch` à chaque nouveau ré-affichage, ce qui modifierait les dépendances du hook `useMemo`, qui appellerait à son tour la fonction d'anti-rebond.
Désormais, React n'appellera la fonction d'anti-rebond que si la fonction `handleSearch` ou le délai change.
Optimisation de la recherche avec l'anti-rebond
Parfois, ralentir peut être plus bénéfique pour les performances. Dans le cadre de la gestion de tâches de recherche, surtout avec des appels de base de données ou d'API coûteux, l'utilisation d'une fonction d'anti-rebond est fortement recommandée. Elle introduit un délai avant l'envoi des requêtes au serveur.
Cela permet de limiter le nombre de requêtes adressées au serveur, car la requête n'est envoyée qu'une fois le délai écoulé et que l'utilisateur a cessé de taper. Ainsi, le serveur n'est pas surchargé par un excès de requêtes et les performances restent efficaces.