React Hook - useCallback
O useCallback
é um dos React Hooks que oferece um meio de otimizar o desempenho de componentes React, especialmente em situações em que há uma re-renderização frequente. Esse Hook é utilizado para memorizar funções e evita que novas instâncias sejam criadas a cada re-renderização, contribuindo para uma execução mais eficiente.
Sintaxe
A sintaxe básica do useCallback
é simples. Ele recebe uma função e um array de dependências. A função será memorizada, ou seja, será recriada apenas quando alguma das dependências no array mudar.
import React, { useCallback } from 'react';
const MeuComponente = () => {
const minhaFuncao = useCallback(() => {
// Lógica da função
}, [/* Dependências */]);
return <button onClick={minhaFuncao}>Clique Aqui</button>;
};
As dependências são cruciais para garantir que o useCallback
funcione corretamente. Se a função utilizada dentro de useCallback
referencia variáveis externas, essas variáveis devem ser incluídas na array de dependências. Caso contrário, a função pode não ser memorizada corretamente.
Caso de uso
O useCallback
é especialmente útil quando uma função é passada como propriedade para componentes filhos, pois ajuda a evitar que esses componentes se re-renderizem desnecessariamente.
import React, { useState, useCallback } from 'react';
function MeuComponente() {
const [contador, setContador] = useState(0);
// Memorizar a função
const handleClick = useCallback(() => {
setContador(contador + 1);
}, [contador]);
return (
<div>
<p>Contador: {contador}</p>
<BotaoIncrementar onClick={handleClick} />
</div>
);
}
function BotaoIncrementar({ onClick }) {
return <button onClick={onClick}>Incrementar</button>;
}
Um problema notável nesse exemplo é que o contador
é uma dependência do useCallback
, o que significa que a função handleClick
é recriada sempre que contador
é alterado. Como resultado, tanto o componente pai (<MeuComponente />
) quanto o componente filho (<BotaoIncrementar />
) são re-renderizados a cada incremento no valor de contador
.
Para solucionar esse problema, podemos utilizar a função React.memo
para memorizar o componente filho e ajustar a lógica da função handleClick
. Agora, a função do setContador
recebe o estado anterior como argumento (prevContador
), eliminando a necessidade de adicionar contador
como uma dependência do useCallback
:
import React, { useState, useCallback } from 'react';
function MeuComponente() {
const [contador, setContador] = useState(0);
// Memorizar a função
const handleClick = useCallback(() => {
setContador((prevContador) => prevContador + 1);
}, []);
return (
<div>
<p>Contador: {contador}</p>
<BotaoIncrementar onClick={handleClick} />
</div>
);
}
// Memorizar o componente
const BotaoIncrementar = React.memo(function BotaoIncrementar({ onClick }) {
return <button onClick={onClick}>Incrementar</button>;
})
Agora, com essa abordagem, conseguimos garantir que a função handleClick
seja memorizada corretamente, evitando re-renderizações desnecessárias e otimizando o desempenho do aplicativo.
Quando usar
useCallback
?O
useCallback
é mais benéfico em situações onde a criação de novas instâncias de funções pode causar re-renderizações desnecessárias de componentes filhos. Em componentes onde a performance não é uma preocupação ou onde funções são definidas diretamente no corpo do componente, o uso deuseCallback
pode não ser tão crítico.