Memoização é uma técnica de otimização que guarda resultados de cálculos ou renders anteriores e os reutiliza quando os mesmos inputs aparecem novamente. No universo React, ela aparece em várias formas (useMemo, useCallback, React.memo) e pode ser poderosa quando aplicada com critério. Este guia explora o porquê, o como, exemplos práticos, armadilhas e alternativas.

O que é memoização?
Esta é uma técnica utilizada para dar velocidade à sistemas computacionais, armazenando o resultado de funções que podem ser consideradas caras para a aplicação. Assim o sistema obtém o valor já computado quando há a necessidade de reutilizar aquele item. Este termo foi cunhado por Donald Michie em 1968 e quer dizer algo como “à ser lembrado” (tradução livre do inglês).
Por que memoizar em React?
O React reconstrói (re-renderiza) componentes quando o estado ou props mudam (isso é desejável e necessário). Mas nem todo re-render custa o mesmo: alguns componentes executam cálculos pesados, criam grandes árvores virtuais, inicializam bibliotecas de terceiros ou provocam efeitos colaterais de alto custo. A memoização ajuda quando:
- Você tem cálculos caros em cada render (filtros, transformações, agregações).
- Componentes filhos re-renderizam desnecessariamente porque recebem novas referências (objetos/funções) vindas do pai.
- Você precisa estabilizar callbacks passados a componentes otimizados (que fazem comparação referencial).
Em síntese: memoize para reduzir trabalho (cálculos) ou re-renderizações custosas.
Principais APIs e técnicas em React
1. useMemo: memoizar valores/cálculos
useMemo armazena o resultado de uma função entre renders enquanto a lista de dependências não mudar.
import { useMemo } from "react";
function ExpensiveList({ items, filter }) {
const filtered = useMemo(
() => items.filter(x => expensiveCheck(x, filter)),
[items, filter]
);
return <List items={filtered} />;
}Quando usar: cálculos pesados que dependem de props/estado.
O que NÃO é: useMemo não impede o componente de re-renderizar — ele apenas evita recalcular o valor. Para prevenir re-render do filho, combine com React.memo ou useCallback.
2. useCallback: memoizar funções
useCallback(fn, deps) retorna a mesma função entre renders enquanto deps não mudarem. É, na prática, equivalente a useMemo(() => fn, deps).
import { useCallback } from "react";
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return <Child onClick={handleClick} />;
}Quando usar: ao passar funções para componentes que usam comparação referencial (por exemplo, React.memo) ou quando você quer estabilizar dependências de outros hooks.
3. React.memo: memoizar componente funcional
React.memo(Component) cria uma versão memoizada que só re-renderiza se suas props mudarem (comparação superficial com Object.is). Útil para componentes puros que recebem props primitivas ou referências estáveis.
const Expensive = React.memo(function Expensive({ items }) {
// render pesado
});Você pode fornecer uma função de comparação customizada (areEqual(prevProps, nextProps)) para casos avançados.
Exemplos práticos – padrões comuns
1. Evitar re-render de listas com React.memo + useCallback
const Row = React.memo(function Row({ item, onSelect }) {
// render do row
});
function Table({ items }) {
const handleSelect = useCallback(id => {
// ...
}, []);
return (
<div>
{items.map(it => (
<Row key={it.id} item={it} onSelect={handleSelect} />
))}
</div>
);
}Sem useCallback, handleSelect seria recriado a cada render do Table, invalidando o React.memo(Row).
2. Memoizando cálculos pesados
function Stats({ data }) {
const stats = useMemo(() => computeHeavyStats(data), [data]);
return <Summary stats={stats} />;
}Medir se computeHeavyStats é realmente custoso: console.time ou o Profiler do React. Se data muda raramente, useMemo compensa.
3. Memoizar render condicional com keys estáveis
Ao renderizar componentes caros com condicionais, prefira manter a mesma instância e controlar visibilidade via CSS ou flags, em vez de desmontar/remontar frequentemente — isso reduz custo de mount/unmount.
Como medir o impacto
Antes de memoizar em massa, meça. Use:
- React DevTools Profiler (marque commits e compare timelines).
- Chrome DevTools Performance / Lighthouse.
- console.time para funções específicas.
Procure “wasted renders” no Profiler: se o componente está re-renderizando sem necessidade e isso corresponde a trabalho pesado, memoização é candidata. Caso contrário, é provável que não traga ganho perceptível.
Desvantagens e riscos da memoização
- Overhead de memória: caches aumentam uso de memória; memoizar tudo pode criar leaks.
- Custo de comparação:
React.memofaz comparação superficial. Comparações customizadas custam CPU; comparar objetos profundos pode ser mais caro do que re-renderizar. - Complexidade mental: o código fica mais difícil de entender; outros devs podem quebrar otimizações passando referências novas por engano.
- Stale closures / referências: usar
useCallbackcom dependências erradas provoca closures que “capturam” valores antigos. - Montagem/desmontagem: evitar re-render via memo pode esconder problemas de arquitetura que seriam melhor resolvidos por composição de componentes.
- Falso senso de segurança: otimizações prematuras causam manutenção difícil sem ganho real.
Acredito que este é um ponto importante a ser reforçado, pois este foi meu principal aprendizado enquanto estava me aprofundando para escrever: memoize quando medido e justificado, não por hábito. Nos últimos anos estive aplicando essas técnicas sem ao menos medir antes e avaliar com mais profundidade cada caso e estudá-lo novamente, me fez repensar em meus hábitos como um desenvolvedor frontend.
Boas práticas e checklist rápido
- Meça antes (Profiler, console.time).
- Memoize apenas cálculos caros e componentes com render pesado.
- Prefira
useMemopara valores/cálculos euseCallbackpara funções passadas a filhos memoizados. - Evite memoizar objetos literais inline, em vez disso, use
useMemopara criar a referência. - Tenha cuidado com dependências: utilize ESLint (plugin
react-hooks) para ajudar a manter array de dependências correto.
Compatibilidade e histórico
React.memofoi introduzido em React 16.6 (outubro de 2018).- Hooks (
useMemo,useCallback) foram adicionados em React 16.8 (fevereiro de 2019). As documentações atuais explicam usos e armadilhas.
Se você mantém bibliotecas que suportam versões antigas (<16.8), não terá hooks; nesse caso, padrões antigos (PureComponent, shouldComponentUpdate) ainda se aplicam.
Exemplos anti-patterns (e como consertá-los)
Anti-pattern: memoizar tudo “por segurança”.
const A = React.memo(function A({ x }) { /* ... */ });
const B = React.memo(function B({ y }) { /* ... */ });Sem medir, você pode introduzir overhead desnecessário. Em muitos casos, a solução é re-estruturar o componente (lift state, split componentes) em vez de memoizar tudo.
Anti-pattern: depender de useMemo para evitar re-renders em vez de estabilizar referências.
// ruim
<Child data={items.map(x => transform(x))} />
// melhor
const transformed = useMemo(() => items.map(x => transform(x)), [items]);
<Child data={transformed} />Ferramentas e bibliotecas úteis
- React DevTools Profiler: para medir commits e render cost.
- ESLint plugin
eslint-plugin-react-hooks: ajuda a manter dependências corretas.
Conclusão
Memoização no React é uma técnica poderosa, porém de uso cirúrgico. Ela resolve problemas reais, focada para cálculos caros, renders custosos e mudanças de referência que disparam re-renderizações, mas traz trade-offs (memória, complexidade e risco de bugs sutis). O fluxo correto é: medir → compreender o custo → aplicar memoização pontual → documentar.
📢 Curtiu essa explicação?
Me siga no LinkedIn para mais conteúdos práticos sobre desenvolvimento frontend.



