Como melhorar o desempenho da pesquisa em reação com debouncing

No React, ao implementar a funcionalidade de pesquisa, o manipulador onChange chama a função de pesquisa toda vez que o usuário digita dentro da caixa de entrada. Essa abordagem pode causar problemas de desempenho, especialmente ao fazer chamadas de API ou consultar o banco de dados. Chamadas frequentes para a função de pesquisa podem sobrecarregar o servidor web, causando travamentos ou falta de resposta da interface do usuário. Debouncing resolve esse problema.

O que é Debouncing?

Normalmente, você implementa a funcionalidade de pesquisa no React chamando uma função manipuladora onChange a cada pressionamento de tecla, conforme mostrado abaixo:

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

Embora isso funcione, a chamada ao back-end para atualizar os resultados da pesquisa a cada pressionamento de tecla pode sair cara. Por exemplo, se você estivesse procurando por “webdev”, a aplicação enviaria uma solicitação ao backend com os valores “w”, “nós”, “web” e assim por diante.

Debouncing é uma técnica que funciona atrasando a execução de uma função até que um período de atraso tenha decorrido. A função debounce detecta toda vez que o usuário digita e evita a chamada para o manipulador de pesquisa até que o atraso tenha decorrido. Se o usuário continuar digitando dentro do período de atraso, o cronômetro será zerado e o React chamará a função novamente para o novo atraso. Esse processo continua até que o usuário faça uma pausa na digitação.

  Corrigir erro PS4 CE-32895-7

Ao esperar que os usuários pausem a digitação, o debouncing garante que seu aplicativo faça apenas as solicitações de pesquisa necessárias, reduzindo assim a carga do servidor.

Como rejeitar a pesquisa no React

Existem várias bibliotecas que você pode usar para implementar o debounce. Você também pode optar por implementá-lo do zero usando as funções setTimeout e clearTimeout do JavaScript.

Este artigo usa a função debounce da biblioteca lodash.

Supondo que você tenha um projeto React pronto, crie um novo componente chamado Search. Se você não tiver um projeto em funcionamento, crie um aplicativo React usando o utilitário create React app.

No arquivo do componente de pesquisa, copie o código a seguir para criar uma caixa de entrada de pesquisa que chama uma função de manipulador a cada pressionamento de tecla.

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

Para debounce a função handleSearch, passe-a para a função debounce do 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..."
    />
  );
}

Na função debounce, você está passando a função que deseja atrasar, ou seja, a função handleSearch, e o tempo de atraso em milissegundos, ou seja, 500ms.

  6 melhores ferramentas para monitoramento de redes, servidores e aplicativos

Embora o código acima deva atrasar a chamada para a solicitação handleSearch até que o usuário pause a digitação, ele não funciona no React. Explicaremos o porquê na seção seguinte.

Debouncing e Rerenderizações

Este aplicativo usa uma entrada controlada. Isto significa que o valor do estado controla o valor da entrada; toda vez que um usuário digita no campo de pesquisa, o React atualiza o estado.

No React, quando um valor de estado muda, o React renderiza novamente o componente e executa todas as funções dentro dele.

No componente de pesquisa acima, quando o componente é renderizado novamente, o React executa a função debounce. A função cria um novo cronômetro que monitora o atraso e o cronômetro antigo fica na memória. Quando o tempo passa, ele aciona a função de busca. Isso significa que a função de pesquisa nunca é cancelada, ela é atrasada em 500 ms. Este ciclo se repete a cada renderização – a função cria um novo cronômetro, o cronômetro antigo expira e então chama a função de pesquisa

Para que a função debounce funcione, você precisa chamá-la apenas uma vez. Você pode fazer isso chamando a função debounce fora do componente ou usando a técnica de memoização. Dessa forma, mesmo que o componente seja renderizado novamente, o React não o executará novamente.

Definindo a função Debounce fora do componente de pesquisa

Mova a função debounce para fora do componente Search, conforme mostrado abaixo:

 import debounce from "lodash.debounce"

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

const debouncedSearch = debounce(handleSearch, 500);

Agora, no componente Search, chame debouncedSearch e passe o termo de pesquisa.

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

A função de pesquisa só será chamada após decorrido o período de atraso.

  10 ferramentas de análise de dados de IA para melhores decisões de negócios

Memorizando a função Debounce

Memoizar refere-se a armazenar em cache os resultados de uma função e reutilizá-los quando você chama a função com os mesmos argumentos.

Para memorizar a função debounce, use o gancho 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..."
    />
  );
}

Observe que você também envolveu a função handleSearch em um gancho useCallback para garantir que o React a chame apenas uma vez. Sem o gancho useCallback, o React executaria a função handleSearch a cada nova renderização, fazendo com que as dependências do gancho useMemo mudassem, o que por sua vez chamaria a função debounce.

Agora, o React só chamará a função debounce se a função handleSearch ou o tempo de atraso mudar.

Otimize a pesquisa com Debounce

Às vezes, desacelerar pode ser melhor para o desempenho. Ao lidar com tarefas de pesquisa, especialmente com chamadas caras de banco de dados ou API, usar uma função debounce é a melhor opção. Esta função introduz um atraso antes de enviar solicitações de backend.

Ajuda a reduzir o número de solicitações feitas ao servidor, pois só envia a solicitação depois de decorrido o atraso e o usuário pausar a digitação. Dessa forma, o servidor não fica sobrecarregado com muitas solicitações e o desempenho permanece eficiente.