Voltar ao Blog
    React
    Performance

    React Server Components em Produção: O Que Ninguém Te Conta em 2026

    RSC saiu do hype e entrou em produção real com Next.js 15 e React Router 7. Menos JavaScript no cliente, dados direto do servidor. Mas a curva de aprendizado é brutal e o modelo mental muda tudo. Lições de quem migrou.

    Publicado em ·12 min de leitura·por Bernardo Gomes

    React Server Components (RSC) foram anunciados em 2020, ficaram experimentais por anos e finalmente, em 2026, são produção mainstream. Next.js 15 os tornou default, React Router 7 os suporta e até frameworks menores aderiram. A promessa: componentes que rodam no servidor, enviando HTML e dados sem mandar JavaScript pro cliente. A realidade: poderoso, mas exige reaprender React.

    ⚠️

    RSC não é 'React mais rápido'. É um modelo mental diferente. Server Components não têm estado, não têm efeitos, não acessam o DOM. Tentar usar useState num Server Component é o erro número 1 de quem migra. Entenda a divisão antes de escrever uma linha.

    Server vs Client: a divisão fundamental

    Por padrão, todo componente em um app RSC é Server Component: roda no servidor, pode buscar dados direto (async/await no componente!), e não envia JS pro cliente. Quando você precisa de interatividade — estado, eventos, hooks de browser — marca o componente com 'use client'. A arte está em manter a fronteira client o menor possível.

    typescript
    // Server Component (padrão) — busca dados direto, zero JS no cliente
    async function ProjectList() {
      // Sem useEffect, sem useState, sem loading state manual
      const res = await fetch("https://api.github.com/users/bernardopg/repos");
      const projects = await res.json();
    
      return (
        <ul>
          {projects.map((p) => (
            // LikeButton é a ÚNICA parte que vira JS no cliente
            <li key={p.id}>
              {p.name}
              <LikeButton projectId={p.id} />
            </li>
          ))}
        </ul>
      );
    }
    
    // Client Component — só o que precisa de interatividade
    "use client";
    import { useState } from "react";
    
    function LikeButton({ projectId }: { projectId: number }) {
      const [liked, setLiked] = useState(false);
      return (
        <button onClick={() => setLiked(!liked)}>
          {liked ? "★" : "☆"}
        </button>
      );
    }
    💡

    A regra de ouro: 'use client' marca uma FRONTEIRA, não um arquivo isolado. Tudo importado por um Client Component também vira client. Coloque o 'use client' o mais fundo possível na árvore — nas folhas interativas, não no topo.

    O ganho real de performance

    O benefício concreto é o bundle de JavaScript. Um app RSC bem feito envia só o JS dos Client Components — frequentemente 30-50% menos que um SPA equivalente. Menos JS = parse mais rápido, Time to Interactive menor, melhor INP. Para conteúdo (blogs, e-commerce, dashboards), o ganho de Core Web Vitals é mensurável.

    • Bundle inicial: 30-50% menor (só Client Components vão pro cliente)
    • Data fetching: sem waterfalls de useEffect — dados resolvem no servidor em paralelo
    • SEO: HTML completo no primeiro byte, sem hidratação para conteúdo estático
    • Segredos seguros: API keys e queries ficam no servidor, nunca no bundle

    As armadilhas que me pegaram

    typescript
    // ARMADILHA 1: passar função de Server pra Client
    // Server Component NÃO pode passar callbacks pra Client Component
    // (funções não serializam pela fronteira)
    
    // ERRADO:
    function ServerParent() {
      const handleClick = () => console.log("oi"); // server-side
      return <ClientChild onClick={handleClick} />; // ❌ erro
    }
    
    // CERTO: passe dados serializáveis, lógica fica no client
    function ServerParent() {
      return <ClientChild projectId={42} />; // ✅ número serializa
    }
    
    // ARMADILHA 2: usar API de browser em Server Component
    function Bad() {
      const w = window.innerWidth; // ❌ window não existe no servidor
      return <div>{w}</div>;
    }
    ⚠️

    A fronteira server/client só aceita dados serializáveis: strings, números, objetos planos, arrays. Funções, classes, Dates complexas e Symbols não atravessam. Esse é o erro mais comum e o compilador nem sempre avisa de forma clara.

    Vale a pena para o seu projeto?

    Depende. Para apps com muito conteúdo dinâmico, fetching pesado e necessidade de SEO, RSC é transformador. Para uma SPA pequena e interativa como este portfólio, o overhead de complexidade não compensa — Vite + React Router client-side com HTML pré-gerado entrega Core Web Vitals excelentes sem o peso conceitual do RSC. Use a ferramenta certa, não a mais nova.

    💡

    Se você está começando um projeto novo com Next.js em 2026, RSC já é o caminho default e vale aprender. Se tem um SPA Vite funcionando bem, não migre por FOMO. RSC resolve problemas específicos de fetching e bundle — se você não tem esses problemas, não precisa da solução.