O Performance Killer Silencioso no seu Código Javascript
Profile picture

Junior Alves

Senior Developer

Foto: Unsplash

Atualizado: 28 de julho de 2025 às 05:49

Leitura: 6 minutos de leitura

Criado: 28 de julho de 2025

O Performance Killer Silencioso no seu Código Javascript

Por que a Referential Equality está custando a performance da sua aplicação React.js?

Introdução

Você já usou o Profiler do React e se perguntou "Por que car@lh# este componente está renderizando de novo?!". Muitas vezes, a causa não é uma mudança de estado óbvia, mas sim um conceito fundamental do Javascript que age nas sombras: a Igualdade Referencial.

Nesse artigo, vamos entender a fundo esse conceito, como ele silenciosamente degrada a performance da sua aplicação e aprender a usar as ferramentas que o React nos dá para domar esse conceito.

O Problema: A Igualdade Referencial

Antes de qualquer solução, precisamos entender claramente o problema. Em Javascript, a forma como a igualdade (===) é verificada difere drasticamente entre tipos de dados.

  • Tipos Primitivos (string, number, boolean): São comparados por valor. 10 === 10 é true. Simples.
  • Tipos de Objeto (object, array, function): São comparados por referência, ou seja, pelo seu endereço na memória.

Isso significa que dois objetos com conteúdo idêntico não são iguais se não forem o mesmo objeto na memória.

// Mesmo que o conteúdo seja idêntico...
const obj1 = { id: 1 };
const obj2 = { id: 1 };
 
// ...eles não são o mesmo objeto na memória.
console.log(obj1 === obj2); // false

E por que isso é um "assassino de performance" em React?

Um componente React é uma função que executa novamente a cada renderização. Qualquer objeto, array ou função declarada dentro dele é recriada do zero, recebendo um novo endereço de memória a cada vez.

Quando o React vai renderizar um componente filho, ele verifica se as props mudaram usando a comparação ===. Para o React, uma nova referência significa uma nova prop, o que aciona uma nova renderização, mesmo que o conteúdo da prop seja visualmente o mesmo. Esse é o ciclo de renderizações desnecessárias que deixa seu app lento.

Entender o "porquê" disso é crucial, pois sem ele, você estará constantemente lutando contra os mecanismos de otimização do React em vez de usá-los a seu favor.

A Solução: Memoization

É aqui que entra a memoization. Essa é uma técnica de otimização que permite que o React "lembre" de coisas (o resultado de um cálculo, uma função, ou um componente renderizado) e pule o trabalho de recriá-las se os inputs não tiverem mudado.

Eu pessoalmente já vi como a aplicação estratégica de memoization pode transformar um dashboard lento e terrível de mexer em uma experiência de usuário fluida e rápida. Bora ver como.

Ferramentas de Memoization do React

O React nos oferece três ferramentas principais para domar a igualdade referencial. Cada uma tem um propósito específico.

1. React.memo(): Memoizando Componentes

É um HOC (Higher-Order Component) que envolve um componente. Ele impede a re-renderização desse componente se suas props não tiverem sofrido alteração de referência. É a sua primeira linha de defesa.

2. useMemo(): Memoizando Valores

Este hook memoiza um valor, como um objeto ou o resultado de um cálculo caro. Você o usa para duas coisas principais:

  1. Evitar re-executar um cálculo pesado a cada render.
  2. Garantir a mesma referência de um objeto ou array que será passado como prop para um componente filho memoizado com React.memo.

3. useCallback(): Memoizando Funções

Similar ao useMemo, mas específico para funções. Seu propósito é garantir que a referência de uma função permaneça estável entre as renderizações. Seus principais usos são:

  1. Passar uma função como prop para um componente filho memoizado com React.memo.
  2. Servir como uma dependência estável para outros hooks, como useEffect, evitando loops infinitos.

Aplicação Prática: Antes e Depois

Vamos ver um exemplo prático. Considere este componente UserProfile que renderiza um Dashboard e um Button.

Antes (O Problema)

// Componentes simples (sem memoization)
const Dashboard = ({ options }: { options: { color: string } }) => {
  console.log('Dashboard re-renderizou!');
  return <div style={{ color: options.color }}>Dashboard</div>;
};
 
const Button = ({
  children,
  ...rest
}: ButtonHTMLAttributes<HTMLButtonElement>) => {
  console.log('Button: re-render');
  return <button {...rest}>{children}</button>;
};
 
// Componente Pai
const UserProfile = () => {
  // A cada render, 'options' e 'handleSave' recebem uma nova referência.
  const options = { color: 'blue' };
  const handleSave = () => console.log('salvando...');
 
  return (
    <>
      <Dashboard options={options} />
      <Button onClick={handleSave}>Salvar</Button>
    </>
  );
};

Neste cenário, qualquer renderização de UserProfile fará com que Dashboard e Button re-renderizem, pois as referências de options e handleSave são sempre novas.

Depois (A Solução)

import { memo, useMemo, useCallback } from 'react';
 
// 1. Memoizamos os componentes filhos com React.memo()
const Dashboard = ({ options }: { options: { color: string } }) => {
  console.log('Dashboard: re-render');
  return <div style={{ color: options.color }}>Dashboard</div>;
};
 
const DashboardMemoized = memo(Dashboard);
 
const Button = ({
  children,
  ...rest
}: ButtonHTMLAttributes<HTMLButtonElement>) => {
  console.log('Button: re-render');
  return <button {...rest}>{children}</button>;
};
 
const ButtonMemoized = memo(Button);
 
// Componente Pai
const UserProfile = () => {
  // 2. Usamos useMemo para estabilizar a referência do objeto 'options'.
  const options = useMemo(() => ({ color: 'blue' }), []);
 
  // 3. Usamos useCallback para estabilizar a referência da função 'handleSave'.
  const handleSave = useCallback(() => {
    console.log('salvando...');
  }, []);
 
  return (
    <>
      <DashboardMemoized options={options} />
      <ButtonMemoized onClick={handleSave}>Salvar</ButtonMemoized>
    </>
  );
};

Agora, o "time" está completo. useMemo e useCallback garantem que as props tenham referências estáveis, e React.memo usa essa estabilidade para inteligentemente pular re-renderizações desnecessárias.

Cuidado...

Apesar de poderosa, a memoization não é uma bala de prata. O verdadeiro "inimigo" não são as re-renderizações, mas as re-renderizações desnecessárias. Aplicar memoization em tudo pode na verdade piorar a performance, pois adiciona uma sobrecarga de memória e de comparação. A regra de ouro é: meça primeiro, otimize depois. Use o React Profiler para encontrar os gargalos.

Nota

Importante ressaltar que com o React Compiler, o processo de memoization acontecerá de forma automática.

O que, na minha opinião, torna ainda mais necessário entender esse processo que acontecerá "por de baixo dos panos".

Testando seu entendimento

Qual é o principal problema que a 'Igualdade Referencial' causa em componentes React, levando a re-renderizações desnecessárias?

1 / 5

Conclusão

Eu lembro daquele momento "aha!" quando este conceito finalmente clicou para mim, ao depurar um componente de dashboard particularmente lento. A sensação de alívio, e o ganho de performance, foi sensacional.

Ao entender e aplicar estrategicamente a memoization, você não está apenas escrevendo "código mais limpo"; você está assumindo o controle da performance da sua aplicação e transformando a experiência do seu usuário de frustração para fluidez.

Agora, dê uma olhada nas suas aplicações. Abra o React DevTools, encontre um ponto de renderização suspeito e veja se consegue rastreá-lo até um problema de igualdade referencial.

Deixe seus feedbacks nos comentários! Grande abraço e até a próxima.

Curtiu? Compartilhe esse post:

Todos os direitos reseverdos © Junior Alves 2025