DevPath · Aprenda a programar ESPTEN

Hooks personalizados e desempenho

Desempenho: por que o React re-renderiza

Por que um componente re-renderiza?

O React re-renderiza um componente quando:

Esse terceiro ponto é fundamental: por padrão, se um pai re-renderiza, todos os seus filhos re-renderizam em cascata. Quase sempre isso é barato e não acontece nada. Mas quando uma subárvore é pesada, convém ter ferramentas para evitar trabalho desnecessário.

React.memo: memoiza um componente

React.memo envolve um componente para que ele só re-renderize se suas props mudarem (comparação superficial). Se o pai repinta mas as props do filho são as mesmas, o React reutiliza o render anterior:

const ListaPesada = React.memo(function ListaPesada({ items }) {
  // render custoso...
  return <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>;
});

Só é útil se as props se mantiverem estáveis entre renders. Aí entram os dois hooks seguintes.

useMemo: memoiza um valor calculado

useMemo lembra o resultado de um cálculo e só o recalcula se mudar alguma de suas dependências. Ideal para cálculos caros:

const ordenados = useMemo(() => {
  return [...items].sort((a, b) => a - b); // cálculo caro
}, [items]); // só recalcula se 'items' mudar

Sem useMemo, esse sort rodaria a cada render. Com ele, só quando items muda.

useCallback: memoiza uma função

A cada render são criadas funções novas. Se você passa uma função como prop para um componente envolto em React.memo, essa prop "muda" sempre e a memoização se quebra. useCallback estabiliza a identidade da função:

const manejarClique = useCallback(() => {
  setSelecao(id);
}, [id]); // mesma função enquanto 'id' não mudar

useCallback(fn, deps) é equivalente a useMemo(() => fn, deps): um memoiza a função, o outro seu resultado.

Regra mental: useMemo para valores, useCallback para funções, React.memo para componentes. Os três comparam dependências/props para decidir se podem pular trabalho.

Exemplos

useMemo evita recalcular se as dependências não mudam

let calculos = 0;
function calcularCaro(n) { calculos++; return n * 2; }
// Render 1
const a = calcularCaro(21);
// Render 2 com a mesma entrada -> com useMemo NÃO recalcularia
console.log("resultado:", a, "| vezes calculado:", calculos);
Coloque isto em prática

O DevPath é um curso prático: aqui você lê a teoria; no app você a coloca em prática com exercícios que rodam de verdade, offline.

Comece grátis no app →
← Hooks personalizados: lógica com estado reutilizávelQuando (e quando não) otimizar →