Jak poprawić wydajność wyszukiwania w reakcji na odrzucenie

W React, podczas implementowania funkcji wyszukiwania, procedura obsługi onChange wywołuje funkcję wyszukiwania za każdym razem, gdy użytkownik wpisze tekst w polu wprowadzania. Takie podejście może powodować problemy z wydajnością, szczególnie w przypadku wykonywania wywołań API lub wysyłania zapytań do bazy danych. Częste wywołania funkcji wyszukiwania mogą przeciążać serwer WWW, powodując awarie lub brak reakcji interfejsu użytkownika. Odbijanie rozwiązuje ten problem.

Co to jest odbijanie?

Zwykle implementujesz funkcję wyszukiwania w React, wywołując funkcję obsługi onChange przy każdym naciśnięciu klawisza, jak pokazano poniżej:

 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..."
    />
  );
}

Chociaż to działa, wywołanie zaplecza w celu aktualizacji wyników wyszukiwania przy każdym naciśnięciu klawisza może być kosztowne. Na przykład, jeśli szukasz „webdev”, aplikacja wyśle ​​żądanie do backendu z wartościami „w”, „we”, „web” i tak dalej.

Odbijanie to technika polegająca na opóźnianiu wykonania funkcji do momentu upłynięcia okresu opóźnienia. Funkcja odrzucania wykrywa za każdym razem, gdy użytkownik napisze i zapobiega wywołaniu modułu obsługi wyszukiwania do momentu upłynięcia opóźnienia. Jeśli użytkownik będzie kontynuował pisanie w określonym czasie, licznik czasu zostanie zresetowany, a React ponownie wywoła funkcję z nowym opóźnieniem. Proces ten trwa, dopóki użytkownik nie przestanie pisać.

Czekając, aż użytkownicy przestaną pisać, odrzucanie zapewnia, że ​​aplikacja wysyła tylko niezbędne żądania wyszukiwania, zmniejszając w ten sposób obciążenie serwera.

Jak odrzucić wyszukiwanie w React

Istnieje kilka bibliotek, których można użyć do zaimplementowania debounce. Możesz także zaimplementować go samodzielnie od podstaw, korzystając z funkcji setTimeout i clearTimeout języka JavaScript.

W tym artykule użyto funkcji debounce z biblioteki lodash.

Zakładając, że masz gotowy projekt React, utwórz nowy komponent o nazwie Search. Jeśli nie masz działającego projektu, utwórz aplikację React za pomocą narzędzia do tworzenia aplikacji React.

W pliku komponentu Search skopiuj poniższy kod, aby utworzyć pole wprowadzania wyszukiwania, które wywołuje funkcję obsługi po każdym naciśnięciu klawisza.

 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..."
    />
  );
}

Aby zdezaktywować funkcję handleSearch, przekaż ją do funkcji debounce z 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..."
    />
  );
}

W funkcji debounce przekazujesz funkcję, którą chcesz opóźnić, np. funkcję handleSearch, i czas opóźnienia w milisekundach, tj. 500 ms.

Chociaż powyższy kod powinien opóźniać wywołanie żądania handleSearch do czasu, aż użytkownik przestanie pisać, nie działa on w React. Wyjaśnimy dlaczego w następnej sekcji.

Odbijanie i ponowne renderowanie

Ta aplikacja wykorzystuje kontrolowane wejście. Oznacza to, że wartość stanu kontroluje wartość wejścia; za każdym razem, gdy użytkownik wpisze w polu wyszukiwania, React aktualizuje stan.

W React, gdy zmienia się wartość stanu, React ponownie renderuje komponent i wykonuje wszystkie zawarte w nim funkcje.

W powyższym komponencie wyszukiwania, gdy komponent zostanie ponownie wyrenderowany, React wykonuje funkcję odrzucania. Funkcja tworzy nowy timer, który śledzi opóźnienie, a stary timer jest przechowywany w pamięci. Po upływie czasu uruchamia funkcję wyszukiwania. Oznacza to, że funkcja wyszukiwania nigdy nie jest odrzucana, jest opóźniona o 500 ms. Cykl ten powtarza się przy każdym renderowaniu — funkcja tworzy nowy licznik czasu, stary licznik czasu wygasa, a następnie wywołuje funkcję wyszukiwania

Aby funkcja odbicia zadziałała, musisz ją wywołać tylko raz. Można to zrobić wywołując funkcję debounce poza komponentem lub stosując technikę zapamiętywania. W ten sposób, nawet jeśli komponent zostanie ponownie wyrenderowany, React nie wykona go ponownie.

Definiowanie funkcji odbijania poza komponentem wyszukiwania

Przenieś funkcję odrzucania poza komponent Wyszukiwanie, jak pokazano poniżej:

 import debounce from "lodash.debounce"

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

const debouncedSearch = debounce(handleSearch, 500);

Teraz w komponencie Search wywołaj debouncedSearch i podaj wyszukiwane hasło.

 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..."
    />
  );
}

Funkcja wyszukiwania zostanie wywołana dopiero po upływie okresu opóźnienia.

Zapamiętywanie funkcji odbicia

Zapamiętywanie oznacza buforowanie wyników funkcji i ponowne ich wykorzystywanie podczas wywoływania funkcji z tymi samymi argumentami.

Aby zapamiętać funkcję debounce, użyj haka 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..."
    />
  );
}

Zauważ, że funkcję handleSearch opakowałeś w hak useCallback, aby mieć pewność, że React wywoła ją tylko raz. Bez haka useCallback React wykonywałby funkcję handleSearch przy każdym ponownym renderowaniu, tworząc zależności zmiany haka useMemo, co z kolei wywołałoby funkcję debounce.

Teraz React wywoła funkcję debounce tylko wtedy, gdy zmieni się funkcja handleSearch lub czas opóźnienia.

Zoptymalizuj wyszukiwanie za pomocą Debounce

Czasami spowolnienie może być lepsze dla wydajności. Podczas obsługi zadań wyszukiwania, szczególnie w przypadku kosztownych wywołań baz danych lub API, najlepszym rozwiązaniem jest użycie funkcji odrzucania. Ta funkcja wprowadza opóźnienie przed wysłaniem żądań zaplecza.

Pomaga zmniejszyć liczbę żądań kierowanych do serwera, ponieważ wysyła żądanie dopiero po upływie opóźnienia i wstrzymaniu pisania przez użytkownika. W ten sposób serwer nie zostanie przeciążony zbyt dużą liczbą żądań, a wydajność pozostanie wydajna.