Quanto mais eu trabalho com React, especialmente em features que começam a ficar mais “parrudas”, mais a palavra “performance” começa a piscar na minha cabeça. No começo, a gente não se liga muito nisso, mas depois de um tempo, evitar re-renders desnecessários vira quase um jogo. Uma das coisas que eu precisei entender melhor como otimizar componentes em foi o hook useMemo
.
Afinal, o que é useMemo
?
Pra ser direto, o useMemo
é um hook do React que “memoriza” o resultado de um cálculo pesado. A palavra-chave aqui é resultado. Ele não guarda a função, mas sim o valor que ela retorna.
Imagina que você tem uma função que demora um pouco pra rodar — tipo filtrar uma lista gigante de dados ou fazer uma computação matemática complexa. Sem o useMemo
, essa função rodaria toda vez que o seu componente renderizasse de novo. E um componente renderiza por vários motivos, né? Mudança de estado, novas props… qualquer coisinha.
O useMemo
entra em cena pra falar: “Opa, calma aí. Se os dados que essa função usa não mudaram, não precisa calcular tudo de novo. Pega aqui o resultado da última vez, que eu guardei pra você”.
É basicamente um cache para o resultado de uma função. Simples assim.
Como a mágica acontece?
A lógica é bem clara. O useMemo
precisa de duas coisas:
- Uma função de “criação”: É a função que faz o trabalho pesado e retorna o valor que você quer guardar.
- Uma lista de dependências: Esse é o pulo do gato. É um array
[]
onde você coloca todas as variáveis (props, estados, etc.) que a sua função usa pra fazer o cálculo.
Funciona mais ou menos assim:
- Na primeira renderização: O React executa sua função, pega o resultado e guarda numa “gavetinha”.
- Nas próximas renderizações: O React olha pra lista de dependências. Ele compara cada item do array com o valor que ele tinha na renderização anterior.
- Se nada mudou, ele simplesmente pega o resultado que estava na gaveta e te entrega. A sua função nem chega a ser executada.
- Se pelo menos uma dependência mudou, aí sim o React executa a função de novo, atualiza o valor na gaveta e te entrega o novo resultado.
Vamos ver um exemplo prático. Foi assim que a ficha realmente caiu pra mim:
import React, { useMemo } from "react";
function ProductList({ products, searchTerm }) {
// A parte pesada é essa filtragem aqui
const visibleProducts = useMemo(() => {
console.log("Opa, filtrando a lista de novo... Isso deveria ser raro!");
return products.filter((product) =>
product.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
}, [products, searchTerm]); // <-- As dependências!
return (
<ul>
{visibleProducts.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
Nesse código, a filtragem da lista products
só vai acontecer de verdade se a própria lista products
mudar ou se o searchTerm
for alterado. Se o componente ProductList
precisar renderizar de novo por qualquer outro motivo (por exemplo, um estado no componente pai que não tem nada a ver com isso mudou), o React vai pular o filter
e reutilizar a lista visibleProducts
que já tinha sido calculada. O console.log
ali é a prova dos nove – você vai ver que ele não dispara toda hora.
Mas atenção: useMemo
não é bala de prata
Aqui foi outra lição importante. Minha primeira reação foi querer sair colocando useMemo
em tudo. “Vou otimizar tudo!”.
Usar useMemo
tem um custo. O React precisa guardar esse valor em memória e, a cada renderização, precisa comparar as dependências. Para cálculos muito simples e rápidos, o custo de usar o useMemo
pode ser maior do que o benefício. Fazer useMemo(() => 2 + 2, [])
é um exemplo bobo, mas ilustra o ponto.
Então, a minha regra de bolso passou a ser:
- Isso é um cálculo realmente pesado ou caro? (Ex: iterar sobre um array de milhares de itens).
- A função está sendo chamada com os mesmos inputs várias vezes, causando re-renders desnecessários?
- O valor que estou memoizando é “referencialmente estável”? (Ou seja, estou evitando que um objeto ou array seja recriado a cada render, o que faria componentes filhos renderizarem de novo?).
Se a resposta for “sim” para alguma dessas perguntas, aí o useMemo
brilha. Caso contrário, provavelmente é um exagero. No final das contas, ele é uma ferramenta de otimização, e a gente só otimiza o que realmente precisa ser otimizado.