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.
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 JavaScript setTimeout e limparTimeout funções.
Este artigo usa a função debounce da biblioteca lodash.
Supondo que você tenha um projeto React pronto, crie um novo componente chamado Procurar. Se você não tiver um projeto em funcionamento, crie um aplicativo React usando o utilitário create React app.
No Procurar arquivo de componente, copie o código a seguir para criar uma caixa de entrada de pesquisa que chama uma função de manipulador em 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 desbancar o identificadorSearch função, passe-a para o rebater função de 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..."
/>
);
}
No rebater função, você está passando a função que deseja atrasar, ou seja, o identificadorSearch função e o tempo de atraso em milissegundos, ou seja, 500ms.
Embora o código acima deva atrasar a chamada para o identificadorSearch request até que o usuário pause a digitação, isso 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 o rebater funcionar fora do Procurar componente conforme mostrado abaixo:
import debounce from "lodash.debounce"const handleSearch = (searchTerm) => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 500);
Agora, no Procurar componente, chamada 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.
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 o rebater função, use o useMemo gancho.
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 embrulhou o identificadorSearch funcionar em um useCallback hook para garantir que o React o chame apenas uma vez. Sem o useCallback gancho, o React executaria o identificadorSearch função com cada re-renderização fazendo as dependências do useMemo mudança de gancho que por sua vez chamaria o rebater função.
Agora, o React só chamará o rebater funcionar se o identificadorSearch função ou o tempo de atraso muda.
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.