Come migliorare le prestazioni di ricerca in React With Debouncing

In React, quando si implementa la funzionalità di ricerca, il gestore onChange chiama la funzione di ricerca ogni volta che l’utente digita nella casella di input. Questo approccio può causare problemi di prestazioni, soprattutto se si effettuano chiamate API o si eseguono query sul database. Le chiamate frequenti alla funzione di ricerca possono sovraccaricare il server Web, causando arresti anomali o la mancata risposta dell’interfaccia utente. Il debouncing risolve questo problema.

Cos’è il debouncing?

In genere, implementi la funzionalità di ricerca in React chiamando una funzione del gestore onChange ad ogni pressione di un tasto, come mostrato di seguito:

 import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    
    handleSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Sebbene funzioni, la chiamata al backend per aggiornare i risultati della ricerca ad ogni pressione di un tasto può diventare costosa. Ad esempio, se stavi cercando “webdev”, l’applicazione invierebbe una richiesta al backend con i valori “w”, “noi”, “web” e così via.

Il debouncing è una tecnica che funziona ritardando l’esecuzione di una funzione fino allo scadere di un periodo di ritardo. La funzione antirimbalzo rileva ogni volta che l’utente digita e impedisce la chiamata al gestore di ricerca fino allo scadere del ritardo. Se l’utente continua a digitare entro il periodo di ritardo, il timer viene ripristinato e React richiama nuovamente la funzione per il nuovo ritardo. Questo processo continua finché l’utente non interrompe la digitazione.

Attendendo che gli utenti interrompano la digitazione, il debouncing garantisce che l’applicazione effettui solo le richieste di ricerca necessarie riducendo così il carico del server.

Come eliminare la ricerca in React

Esistono diverse librerie che è possibile utilizzare per implementare il antirimbalzo. Puoi anche scegliere di implementarlo da zero utilizzando le funzioni setTimeout e clearTimeout di JavaScript.

Questo articolo utilizza la funzione antirimbalzo della libreria lodash.

Supponendo che tu abbia un progetto React pronto, crea un nuovo componente chiamato Cerca. Se non hai un progetto funzionante, crea un’app React utilizzando l’utilità di creazione dell’app React.

Nel file del componente di ricerca copiare il codice seguente per creare una casella di input di ricerca che richiama una funzione del gestore a ogni pressione di un tasto.

 import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    
    handleSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Per eliminare il rimbalzo dalla funzione handleSearch, passarla alla funzione antirimbalzo da lodash.

 import debounce from "lodash.debounce";
import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };
  const debouncedSearch = debounce(handleSearch, 1000);

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    
    debouncedSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Nella funzione antirimbalzo, stai passando la funzione che vuoi ritardare, ovvero la funzione handleSearch, e il tempo di ritardo in millisecondi, ovvero 500 ms.

Sebbene il codice precedente dovrebbe ritardare la chiamata alla richiesta handleSearch finché l’utente non interrompe la digitazione, non funziona in React. Spiegheremo perché nella sezione seguente.

Debouncing e Rerender

Questa applicazione utilizza un ingresso controllato. Ciò significa che il valore dello stato controlla il valore dell’input; ogni volta che un utente digita nel campo di ricerca React aggiorna lo stato.

In React, quando il valore di uno stato cambia, React esegue nuovamente il rendering del componente ed esegue tutte le funzioni al suo interno.

Nel componente di ricerca sopra, quando il componente viene nuovamente renderizzato, React esegue la funzione antirimbalzo. La funzione crea un nuovo timer che tiene traccia del ritardo e il vecchio timer rimane in memoria. Allo scadere del tempo, attiva la funzione di ricerca. Ciò significa che la funzione di ricerca non viene mai rimbalzata, ma ritardata di 500 ms. Questo ciclo si ripete ad ogni rendering: la funzione crea un nuovo timer, il vecchio timer scade e quindi chiama la funzione di ricerca

Perché la funzione antirimbalzo funzioni, è necessario chiamarla una sola volta. Puoi farlo chiamando la funzione antirimbalzo all’esterno del componente o utilizzando la tecnica di memorizzazione. In questo modo, anche se il componente viene nuovamente renderizzato, React non lo eseguirà nuovamente.

Definizione della funzione antirimbalzo all’esterno del componente di ricerca

Sposta la funzione antirimbalzo all’esterno del componente Ricerca come mostrato di seguito:

 import debounce from "lodash.debounce"

const handleSearch = (searchTerm) => {
  console.log("Search for:", searchTerm);
};

const debouncedSearch = debounce(handleSearch, 500);

Ora, nel componente Ricerca, chiama debouncedSearch e passa il termine di ricerca.

 export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    
    debouncedSearch(searchTerm);
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

La funzione di ricerca verrà richiamata solo allo scadere del periodo di ritardo.

Memorizzazione della funzione antirimbalzo

La memorizzazione si riferisce alla memorizzazione nella cache dei risultati di una funzione e al loro riutilizzo quando si chiama la funzione con gli stessi argomenti.

Per memorizzare la funzione antirimbalzo, utilizzare il gancio 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("Search for:", 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="Search here..."
    />
  );
}

Tieni presente che hai anche racchiuso la funzione handleSearch in un hook useCallback per assicurarti che React la chiami solo una volta. Senza l’hook useCallback, React eseguirebbe la funzione handleSearch ad ogni re-rendering modificando le dipendenze dell’hook useMemo che a sua volta chiamerebbe la funzione debounce.

Ora, React chiamerà la funzione debounce solo se la funzione handleSearch o il tempo di ritardo cambiano.

Ottimizza la ricerca con Debounce

A volte, rallentare può essere migliore per le prestazioni. Quando si gestiscono attività di ricerca, in particolare con database costosi o chiamate API, utilizzare una funzione antirimbalzo è la strada da percorrere. Questa funzione introduce un ritardo prima dell’invio delle richieste di backend.

Aiuta a ridurre il numero di richieste effettuate al server, poiché invia la richiesta solo dopo che è trascorso il ritardo e l’utente ha interrotto la digitazione. In questo modo il server non viene sovraccaricato da troppe richieste e le prestazioni rimangono efficienti.