Voltar para o Blog

React Compiler em 2026: O Fim do useMemo e useCallback Manual

Olá HaWkers, uma das maiores mudanças no ecossistema React em 2026 é a adoção em massa do React Compiler. A memoização manual que atormentou desenvolvedores por anos está finalmente se tornando coisa do passado.

Vamos entender o que mudou e como escrever React moderno.

O Problema Que o Compiler Resolve

A Dor da Memoização Manual

Por anos, desenvolvedores React precisaram lidar com isso:

// O inferno da memoização manual (como era antes)

import { useMemo, useCallback, memo } from 'react';

interface User {
  id: number;
  name: string;
  email: string;
}

interface UserListProps {
  users: User[];
  onSelect: (user: User) => void;
  filter: string;
}

// Componente memoizado
const UserCard = memo(({ user, onSelect }: {
  user: User;
  onSelect: (user: User) => void;
}) => {
  return (
    <div onClick={() => onSelect(user)}>
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  );
});

function UserList({ users, onSelect, filter }: UserListProps) {
  // useMemo para filtrar users
  const filteredUsers = useMemo(() => {
    return users.filter(u =>
      u.name.toLowerCase().includes(filter.toLowerCase())
    );
  }, [users, filter]);

  // useCallback para estabilizar referência
  const handleSelect = useCallback((user: User) => {
    console.log('Selected:', user);
    onSelect(user);
  }, [onSelect]);

  // useMemo para computação cara
  const stats = useMemo(() => ({
    total: users.length,
    filtered: filteredUsers.length,
    percentage: (filteredUsers.length / users.length * 100).toFixed(1)
  }), [users.length, filteredUsers.length]);

  return (
    <div>
      <p>Mostrando {stats.filtered} de {stats.total} ({stats.percentage}%)</p>
      {filteredUsers.map(user => (
        <UserCard
          key={user.id}
          user={user}
          onSelect={handleSelect}
        />
      ))}
    </div>
  );
}

Problemas dessa abordagem:

  • Código verboso e difícil de ler
  • Fácil esquecer dependências
  • Over-memoization (memoizar coisas que não precisam)
  • Under-memoization (esquecer de memoizar o que precisa)
  • Difícil saber quando memoizar

O React Compiler

Como Funciona

// Com React Compiler (2026) - O MESMO código, sem memoização manual

interface User {
  id: number;
  name: string;
  email: string;
}

interface UserListProps {
  users: User[];
  onSelect: (user: User) => void;
  filter: string;
}

// Sem memo() - compiler otimiza automaticamente
function UserCard({ user, onSelect }: {
  user: User;
  onSelect: (user: User) => void;
}) {
  return (
    <div onClick={() => onSelect(user)}>
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  );
}

// Código limpo e natural
function UserList({ users, onSelect, filter }: UserListProps) {
  // Sem useMemo - compiler detecta e otimiza
  const filteredUsers = users.filter(u =>
    u.name.toLowerCase().includes(filter.toLowerCase())
  );

  // Sem useCallback - compiler estabiliza automaticamente
  const handleSelect = (user: User) => {
    console.log('Selected:', user);
    onSelect(user);
  };

  // Sem useMemo - compiler sabe que é computação derivada
  const stats = {
    total: users.length,
    filtered: filteredUsers.length,
    percentage: (filteredUsers.length / users.length * 100).toFixed(1)
  };

  return (
    <div>
      <p>Mostrando {stats.filtered} de {stats.total} ({stats.percentage}%)</p>
      {filteredUsers.map(user => (
        <UserCard
          key={user.id}
          user={user}
          onSelect={handleSelect}
        />
      ))}
    </div>
  );
}

O que o compiler faz:

  1. Analisa o código em tempo de compilação
  2. Detecta valores que podem ser memoizados
  3. Insere memoização automaticamente onde necessário
  4. Garante que callbacks sejam estáveis
  5. Otimiza re-renders automaticamente

O Que o Compiler Analisa

Detecção Inteligente

// O compiler entende padrões comuns

function ProductPage({ productId }: { productId: string }) {
  const [quantity, setQuantity] = useState(1);

  // Compiler detecta: depende só de productId
  // Memoiza automaticamente
  const product = products.find(p => p.id === productId);

  // Compiler detecta: depende de product e quantity
  // Memoiza e recalcula quando necessário
  const totalPrice = product ? product.price * quantity : 0;

  // Compiler detecta: função que é passada como prop
  // Estabiliza referência automaticamente
  const handleAddToCart = () => {
    addToCart(productId, quantity);
  };

  // Compiler detecta: objeto criado no render
  // Memoiza para evitar re-renders filhos
  const cartItem = {
    productId,
    quantity,
    price: totalPrice
  };

  return (
    <div>
      <h1>{product?.name}</h1>
      <QuantitySelector
        value={quantity}
        onChange={setQuantity}  // setter é estável por natureza
      />
      <p>Total: ${totalPrice}</p>
      <AddToCartButton
        item={cartItem}       // objeto memoizado
        onAdd={handleAddToCart} // callback estabilizado
      />
    </div>
  );
}

Configuração em 2026

Setup Padrão

// next.config.ts (Next.js 15+)
import type { NextConfig } from 'next';

const config: NextConfig = {
  experimental: {
    // React Compiler habilitado por padrão em 2026
    reactCompiler: true,
  },
};

export default config;

// Para projetos Vite
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import reactCompiler from 'babel-plugin-react-compiler';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [reactCompiler],
      },
    }),
  ],
});

ESLint Plugin

// eslint.config.js
import reactCompiler from 'eslint-plugin-react-compiler';

export default [
  {
    plugins: {
      'react-compiler': reactCompiler,
    },
    rules: {
      // Avisa quando código pode ser problemático
      'react-compiler/react-compiler': 'error',
    },
  },
];

Quando Ainda Usar Hooks Manuais

Casos Especiais

// Casos onde memoização manual ainda faz sentido

// 1. Computações MUITO caras com controle fino
function DataVisualization({ data }: { data: number[] }) {
  // Para cálculos que levam segundos, você pode
  // querer controle explícito
  const processedData = useMemo(() => {
    return expensiveStatisticalAnalysis(data);
  }, [data]);

  // Ou usar a nova API useDeferredValue para não bloquear
  const deferredData = useDeferredValue(data);

  return <Chart data={processedData} />;
}

// 2. Integração com bibliotecas externas
function MapComponent({ markers }: { markers: Marker[] }) {
  // Bibliotecas externas podem ter suas próprias
  // regras de comparação
  const memoizedMarkers = useMemo(
    () => markers.map(m => createMapMarker(m)),
    [markers]
  );

  return <ExternalMapLibrary markers={memoizedMarkers} />;
}

// 3. Refs e imperative handles
function VideoPlayer({ src }: { src: string }) {
  const videoRef = useRef<HTMLVideoElement>(null);

  // useCallback ainda útil para imperative APIs
  const play = useCallback(() => {
    videoRef.current?.play();
  }, []);

  const pause = useCallback(() => {
    videoRef.current?.pause();
  }, []);

  // Expondo métodos imperativos
  useImperativeHandle(ref, () => ({
    play,
    pause,
  }), [play, pause]);

  return <video ref={videoRef} src={src} />;
}

Padrões Modernos em 2026

Server Components + Compiler

// Combinando React Server Components com Compiler

// app/products/page.tsx (Server Component)
async function ProductsPage() {
  // Dados buscados no servidor
  const products = await fetchProducts();

  return (
    <div>
      <h1>Produtos</h1>
      {/* Client Component recebe dados serializados */}
      <ProductGrid products={products} />
    </div>
  );
}

// components/ProductGrid.tsx (Client Component)
'use client';

function ProductGrid({ products }: { products: Product[] }) {
  const [filter, setFilter] = useState('');
  const [sort, setSort] = useState<'price' | 'name'>('name');

  // Compiler otimiza tudo automaticamente
  const filtered = products.filter(p =>
    p.name.toLowerCase().includes(filter.toLowerCase())
  );

  const sorted = [...filtered].sort((a, b) => {
    if (sort === 'price') return a.price - b.price;
    return a.name.localeCompare(b.name);
  });

  return (
    <div>
      <FilterInput value={filter} onChange={setFilter} />
      <SortSelect value={sort} onChange={setSort} />
      <div className="grid">
        {sorted.map(product => (
          <ProductCard key={product.id} product={product} />
        ))}
      </div>
    </div>
  );
}

Actions e Mutations

// Padrão moderno com Server Actions

// actions/cart.ts
'use server';

import { revalidatePath } from 'next/cache';

export async function addToCart(productId: string, quantity: number) {
  await db.cart.add({ productId, quantity });
  revalidatePath('/cart');
}

// components/AddToCartButton.tsx
'use client';

import { addToCart } from '@/actions/cart';
import { useTransition } from 'react';

function AddToCartButton({ productId }: { productId: string }) {
  const [isPending, startTransition] = useTransition();
  const [quantity, setQuantity] = useState(1);

  // Compiler otimiza automaticamente
  const handleClick = () => {
    startTransition(async () => {
      await addToCart(productId, quantity);
    });
  };

  return (
    <button onClick={handleClick} disabled={isPending}>
      {isPending ? 'Adicionando...' : 'Adicionar ao Carrinho'}
    </button>
  );
}

Migrando Código Legado

Estratégia de Migração

// Passo 1: Habilite o compiler no projeto

// Passo 2: Remova memoização desnecessária gradualmente

// ANTES
const MemoizedComponent = memo(function Component({ data }) {
  const processed = useMemo(() => process(data), [data]);
  const handler = useCallback(() => doSomething(), []);
  return <div onClick={handler}>{processed}</div>;
});

// DEPOIS
function Component({ data }) {
  const processed = process(data);
  const handler = () => doSomething();
  return <div onClick={handler}>{processed}</div>;
}

// Passo 3: Confie no ESLint plugin para avisar problemas

// Passo 4: Teste performance antes e depois

O Que Remover

// Checklist de migração

const migrationChecklist = {
  // Pode remover com segurança
  safeToRemove: [
    'React.memo() em componentes simples',
    'useMemo() para objetos passados como props',
    'useCallback() para handlers de evento',
    'useMemo() para computações derivadas simples'
  ],

  // Avaliar caso a caso
  evaluate: [
    'useMemo() para computações muito caras',
    'useCallback() em bibliotecas externas',
    'memo() com função de comparação customizada'
  ],

  // Manter
  keep: [
    'useRef() - não é memoização',
    'useState() - não é memoização',
    'useEffect() - side effects',
    'useLayoutEffect() - side effects síncronos'
  ]
};

Performance em 2026

Comparativo

// Resultados típicos de migração

const performanceComparison = {
  bundleSize: {
    before: '145kb',
    after: '142kb',
    note: 'Compiler adiciona pouco overhead'
  },

  developerExperience: {
    before: 'Muitos bugs de dependências esquecidas',
    after: 'Zero preocupação com memoização',
    timesSaved: 'Significativo'
  },

  runtime: {
    before: 'Performance inconsistente',
    after: 'Otimização consistente automática',
    improvement: '10-30% em apps com memoização incorreta'
  },

  codeReadability: {
    before: 'Poluído com hooks de memoização',
    after: 'Limpo e direto ao ponto',
    improvement: 'Significativa'
  }
};

Conclusão

O React Compiler representa uma mudança de paradigma: de "como otimizo isso?" para "escreva código natural e deixe o compiler otimizar".

Principais takeaways:

  1. Memoização manual é coisa do passado - O compiler faz melhor que humanos
  2. Código mais limpo - Foque na lógica, não na otimização
  3. Menos bugs - Sem erros de dependências esquecidas
  4. Performance consistente - Otimização automática e inteligente

Se você ainda não habilitou o React Compiler no seu projeto, 2026 é o ano de fazer isso. A comunidade React já adotou em massa, e os frameworks principais têm suporte first-class.

Para entender mais sobre o ecossistema JavaScript atual, confira: TypeScript É o Padrão em 2026.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário