<h2>Entendendo Memoização em React</h2>
<p>Memoização é uma técnica de otimização que consiste em armazenar o resultado de uma operação custosa e reutilizá-lo quando os mesmos parâmetros são fornecidos novamente. Em React, essa prática é fundamental quando você trabalha com componentes complexos ou aplicações que sofrem com renderizações desnecessárias.</p>
<p>Antes de mergulhar em <code>useMemo</code> e <code>useCallback</code>, é crucial compreender que React renderiza componentes sempre que seu estado ou props mudam. Em muitos casos, isso é eficiente e desejável. Porém, quando você tem cálculos pesados, grandes listas de dados ou funções que são dependências críticas de outros efeitos, memoização torna-se uma ferramenta poderosa. O ponto central é este: memoização não resolve todos os problemas de performance e, quando usada incorretamente, pode até piorá-los.</p>
<h2>useMemo: Guardando Resultados de Cálculos</h2>
<h3>Conceito e Sintaxe</h3>
<p><code>useMemo</code> é um Hook do React que memoriza um valor calculado e só o recalcula quando suas dependências mudam. A sintaxe é simples: você passa uma função que retorna um valor e um array de dependências. Se as dependências não mudarem, React retorna o valor anterior armazenado em memória, economizando processamento.</p>
<pre><code class="language-javascript">const memoizedValue = useMemo(() => {
return expensiveCalculation(a, b);
}, [a, b]);</code></pre>
<h3>Um Exemplo Prático Real</h3>
<p>Imagine um aplicativo que filtra uma lista de usuários e calcula estatísticas. Sem memoização, a filtragem aconteceria em cada renderização, mesmo que os dados não tivessem mudado:</p>
<pre><code class="language-javascript"></code></pre>
<p>Neste exemplo, sem <code>useMemo</code>, se o componente pai re-renderizar por qualquer motivo (como uma mudança de tema ou outro estado), os filtros e cálculos aconteceriam novamente desnecessariamente. Com <code>useMemo</code>, apenas quando <code>users</code> ou <code>searchTerm</code> realmente mudarem é que o cálculo é executado.</p>
<h3>O Custo Real da Memoização</h3>
<p>Aqui está o ponto crítico que muitos desenvolvedores ignoram: <strong>memoização tem um custo</strong>. React precisa comparar as dependências a cada renderização, e se o valor memorizado for primitivo ou muito simples, o overhead dessa comparação pode ser maior que o benefício. Além disso, armazenar em memória consome recursos.</p>
<p>Use <code>useMemo</code> quando você tiver certeza de que:</p>
<ul>
<li>O cálculo é realmente custoso (operações com arrays grandes, cálculos matemáticos complexos)</li>
<li>As dependências mudam com frequência menor que a renderização do componente</li>
<li>O valor é passado como props a componentes que usam <code>React.memo</code></li>
</ul>
<h2>useCallback: Memoizando Funções</h2>
<h3>Por Que Memoizar Funções?</h3>
<p>Funções em JavaScript são objetos. Cada vez que seu componente renderiza, uma nova função é criada, mesmo que o corpo da função seja idêntico. Isso parece inofensivo, mas há cenários onde causa problemas reais: quando você passa uma função como prop para um componente <code>React.memo</code>, a nova função quebra a memoização daquele componente, causando renderizações desnecessárias.</p>
<p><code>useCallback</code> permite que você retorne a mesma instância de função entre renderizações, desde que as dependências não mudem:</p>
<pre><code class="language-javascript">const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);</code></pre>
<h3>Exemplo Prático com Componentes Memoizados</h3>
<pre><code class="language-javascript"></code></pre>
<p>Abra o console e clique no botão "Incrementar". Sem <code>useCallback</code>, você veria "ButtonList renderizado" a cada clique, porque uma nova função é passada como prop. Com <code>useCallback</code>, ButtonList só renderiza se a função realmente mudar (ou se <code>items</code> mudar, neste caso não muda).</p>
<h3>Dependências e Armadilhas Comuns</h3>
<p>O maior erro ao usar <code>useCallback</code> é esquecer de incluir dependências que a função realmente usa. Se sua callback precisa acessar uma variável externa, essa variável deve estar no array de dependências:</p>
<pre><code class="language-javascript"></code></pre>
<p>Note aqui que usamos <code>setCount(prevCount => ...)</code> ao invés de acessar diretamente <code>count</code>. Esta é uma prática importante: sempre que possível, use funções de atualização de estado para evitar dependências desnecessárias.</p>
<h2>Análise de Custo: Quando Usar e Quando Evitar</h2>
<h3>Medir Antes de Otimizar</h3>
<p>A regra de ouro da otimização é: <strong>meça primeiro</strong>. Use as ferramentas de profiling do React (React DevTools Profiler) para identificar onde o tempo está sendo gasto. Muitas vezes, o gargalo não está onde você acha que está.</p>
<pre><code class="language-javascript">// Exemplo de como usar React DevTools Profiler
// 1. Abra React DevTools > Profiler
// 2. Grave uma interação
// 3. Procure por componentes que levam mais tempo
// 4. Identifique se é renderização ou execução do componente
function ExpensiveComponent({ data }) {
// Um cálculo que realmente é custoso
const result = useMemo(() => {
let sum = 0;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < 1000000; j++) {
sum += data[i] * j;
}
}
return sum;
}, [data]);
return <div>{result}</div>;
}</code></pre>
<h3>Tabela de Custos</h3>
<div class="table-wrap"><table><thead><tr><th>Situação</th><th>useMemo</th><th>useCallback</th><th>Recomendação</th></tr></thead><tbody><tr><td>Cálculo simples (strings, números pequenos)</td><td>❌</td><td>❌</td><td>Não use memoização</td></tr><tr><td>Filtro/mapa de grande array</td><td></td></tr><tr><td>-</td><td>Use useMemo</td></tr><tr><td>Função passada a React.memo</td><td>-</td><td></td></tr><tr><td>Use useCallback</td></tr><tr><td>Dependência de useEffect custoso</td><td></td></tr><tr><td></td></tr><tr><td>Use conforme necessário</td></tr><tr><td>Objeto/array como prop</td><td></td></tr><tr><td>-</td><td>Use useMemo para o objeto/array</td></tr><tr><td>Estado derivado simples</td><td>❌</td><td>❌</td><td>Apenas calcule inline</td></tr></tbody></table></div>
<h3>Exemplo: Decisão de Memoização</h3>
<pre><code class="language-javascript"></code></pre>
<h2>Conclusão</h2>
<p>Três aprendizados principais levam você a dominar memoização em React:</p>
<ol>
<li><strong>Memoização é uma ferramenta, não uma solução universal.</strong> Use-a estrategicamente apenas quando mensurar e confirmar que há ganho real. Adicionar <code>useMemo</code> e <code>useCallback</code> em tudo é anti-pattern e prejudica performance.</li>
</ol>
<ol>
<li><strong>As dependências são críticas e exigem atenção.</strong> Esquecer ou incluir dependências erradas quebra a lógica do componente e causa bugs sutis. Use ferramentas como ESLint plugin para React Hooks para evitar erros.</li>
</ol>
<ol>
<li><strong>Entenda o custo: comparação de dependências, armazenamento em memória e complexidade do código.</strong> Às vezes, recalcular é mais barato que memoizar. Perfil suas aplicações com React DevTools antes de aplicar otimizações.</li>
</ol>
<h2>Referências</h2>
<ul>
<li><a href="https://react.dev/reference/react/useMemo" target="_blank" rel="noopener noreferrer">React Official Documentation - useMemo</a></li>
<li><a href="https://react.dev/reference/react/useCallback" target="_blank" rel="noopener noreferrer">React Official Documentation - useCallback</a></li>
<li><a href="https://web.dev/rendering-on-the-web/" target="_blank" rel="noopener noreferrer">Web.dev - React Rendering Behavior</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">Kyle Simpson - You Don't Know JS Yet: Scope & Closures</a></li>
<li><a href="https://www.youtube.com/watch?v=RxjQXaDAkqg" target="_blank" rel="noopener noreferrer">Jack Herrington - React Performance Patterns</a></li>
</ul>
<p><!-- FIM --></p>