No início de 2023, um cliente meu, uma startup de fintech baseada em Canary Wharf, me entregou um codebase Next.js 13 que uma agência anterior havia construído. Estava usando o novo diretório app/. Legal. Exceto que os erros de hidratação estavam em toda parte, o bundle tinha 340 KB comprimido, e ninguém do time antigo conseguia explicar por que tinham colocado "use client" em literalmente cada arquivo. Quando perguntei sobre React Server Components, eles disseram: "Ah sim, usamos esses." Eles não usavam.
Esse é o problema com RSCs agora. Todos afirmam entendê-los. Quase ninguém realmente entende. Então deixa eu te dar a versão que gostaria que tivesse existido no início de 2023.
O Que RSCs Realmente São (Não a Versão de Marketing)
React Server Components são componentes que executam apenas no servidor e nunca enviam seu JavaScript para o navegador. Ponto final.
Não é "renderização do lado do servidor." Não é "pré-renderização." Essas coisas existiam antes de RSCs e funcionam diferentemente. Com SSR tradicional (o que o pages router do Next.js faz), seus componentes renderizam no servidor para produzir HTML, mas então o mesmo JavaScript é enviado ao cliente para que React possa "hidratar" a página, anexar event listeners e assumir o controle.
RSCs pulam a segunda parte inteiramente. O componente executa no servidor, renderiza, envia seu resultado como um payload serializado para o cliente, e então... é isso. Nenhum JavaScript para esse componente jamais chega ao navegador.
O efeito prático: se você tem um componente <ProductDescription> que usa um parser markdown de 40 KB para renderizar algum texto, e você o torna um server component, esse 40 KB nunca vai para o usuário. O HTML parseado vai. É isso.
O RFC original do time React é realmente vale a pena ler se você quer o fundamento completo. É denso mas honesto.
O Modelo Mental Que Finalmente Fez Tudo Fazer Sentido para Mim
Pense na sua árvore de componentes como dois mundos separados que estão costurados juntos.
Mundo 1 (Servidor). Tem acesso total ao seu banco de dados, seu filesystem, suas variáveis de ambiente, seus secrets. Não pode usar useState, useEffect ou nenhuma API de navegador. Não pode anexar event listeners.
Mundo 2 (Cliente). Roda no navegador. Pode usar todos os React hooks que você conhece. Não pode falar diretamente com seu banco de dados. Envia requisições para APIs em vez disso.
Antes dos RSCs, todo componente vivia no Mundo 2, mesmo que fosse renderizado no servidor primeiro. Com RSCs, você agora pode explicitamente colocar componentes no Mundo 1. Esses componentes podem renderizar componentes do Mundo 2 como filhos, passando props serializáveis. Mas componentes do Mundo 2 não podem renderizar componentes do Mundo 1. A barreira é unidirecional.
Aqui é onde as pessoas se confundem: você não adiciona uma diretiva para fazer algo ser um componente de servidor. No diretório app/ do Next.js, tudo é um componente de servidor por padrão. Você entra no cliente com "use client". O oposto do que a maioria das pessoas assume.
A Seahawk teve um projeto ano passado, um grande catálogo de e-commerce para uma varejista do Reino Unido, onde auditamos cerca de 60 componentes. Descobrimos que aproximadamente 40 deles tinham "use client" sem razão nenhuma. Remover isso cortou o bundle de JavaScript em aproximadamente 28%. Um trabalho de uma tarde.
O Que Você Pode e Não Pode Fazer (Um Detalhamento Concreto)
Server Components podem:
- Buscar dados diretamente com async/await, sem useEffect, sem loading states, apenas
const data = await db.query(...) - Importar bibliotecas pesadas exclusivas do servidor (como gray-matter para análise de frontmatter, ou geradores de PDF) sem tocar no bundle do cliente
- Ler do filesystem usando o módulo
fsdo Node - Acessar variáveis de ambiente que você não quer expostas ao navegador
- Passar dados para componentes cliente como props
Server Components não podem:
- Usar
useStateouuseReducer - Usar
useEffectouuseLayoutEffect - Anexar event handlers (sem onClick, sem
onChange) - Usar APIs de navegador (window, document,
localStorage) - Usar React Context diretamente (embora existam padrões para contornar isso)
Client Components podem fazer tudo acima que Server Components não podem, mas:
- Eles não podem chamar diretamente seu banco de dados
- Eles não podem usar pacotes exclusivos do servidor
- Seu código é enviado para o navegador
A questão não é apenas sobre performance. É sobre onde o código é executado e o que ele tem acesso. Esse enquadramento é mais útil do que pensar em termos de "rápido" vs "lento".
Data Fetching é Onde RSCs Realmente Brilham
Esta é a parte que eu realmente amo. Antes dos RSCs, buscar dados em um app Next.js geralmente significava uma destas: getServerSideProps, getStaticProps, uma chamada useEffect no lado do cliente, ou alguma combinação das três com um hook customizado para gerenciar o estado de carregamento. Bagunçado.
Com RSCs, você apenas... faz a busca. Dentro do componente. No nível superior.
`` async function ProductPage({ id }) { const product = await getProduct(id); // calls your DB directly return <ProductDetails product={product} />; } ``
Sem prop drilling de uma função no nível da página. Sem spinners de carregamento para dados que já poderiam estar prontos na chegada. O componente é assíncrono, ele aguarda o que precisa, e renderiza.
E aqui é onde fica genuinamente interessante: porque cada server component pode buscar seus próprios dados independentemente, você evita o antigo problema do "God component" onde uma função no topo tinha que orquestrar todos os dados de uma página inteira. Componentes ficam auto-contidos. Busca paralela acontece naturalmente quando você aguarda Promise.all() ou quando componentes irmãos fazem buscas independentemente.
Usei esse padrão em um projeto de dashboard para uma firma de logística em Birmingham na primavera passada. Cada widget, estatísticas de remessas, alertas de atrasos, resumo de custos, era seu próprio server component assíncrono. Sem estado compartilhado de carregamento, sem prop drilling, sem race conditions. A página passou de um LCP de 2.1 segundos para 0.9 segundos. Não apenas por causa dos RSCs, mas RSCs tornaram a arquitetura correta muito mais fácil de alcançar.
The Rendering Pipeline (O Que Realmente Acontece)
Quando um usuário solicita uma página em um app Next.js 14 usando o router app/, aqui está a sequência aproximada:
- Next.js executa seus server components no servidor
- Esses componentes produzem um formato especial chamado React Server Component Payload (RSC Payload), não HTML bruto, mas uma descrição serializada da árvore de UI
- Next.js usa esse payload para gerar o HTML inicial (para a primeira renderização)
- Esse HTML é enviado para o navegador
- O RSC Payload também é enviado, e o runtime React do cliente o usa para hidratar apenas os componentes do cliente na árvore
- Componentes do cliente recebem seu JavaScript, hidratam, e ficam interativos
O passo 5 é o que torna RSCs diferentes de SSR simples. O cliente não re-renderiza server components. Ele apenas usa o payload para preencher a imagem e depois foca o esforço de hidratação nas partes interativas.
A documentação do Next.js sobre rendering explica o formato do payload melhor do que a maioria dos posts de blog que já li, se você quiser se aprofundar.
Onde RSCs Falham (Crítica Honesta)
Certo. Vamos não fingir que tudo é perfeito.
O limite "use client" faz cascata. No momento em que você coloca "use client" em um componente, todo componente que ele importa também fica do lado do cliente. Se você não tomar cuidado, um manipulador onClick pode puxar uma subtree surpreendentemente grande para o bundle do cliente. Vi isso pegar múltiplas vezes com devs juniores no time.
Context é doloroso. React Context não funciona em server components. Se você construiu sua arquitetura de app em torno de Context para theming, estado de auth, ou config global, você vai precisar reestruturar. Existem workarounds (passar valores como props, usar um wrapper do cliente), mas é atrito que você não tinha antes.
Debugging é mais difícil. Erros de server component não aparecem no console do navegador da mesma forma. O comportamento da error boundary é diferente. Você precisa checar logs do servidor. Não é um dealbreaker, mas se você está acostumado com todos os erros vivendo no DevTools, espere uma curva de aprendizado.
Bibliotecas de terceiros frequentemente não estão prontas. Qualquer biblioteca que usa hooks ou APIs do navegador por baixo vai quebrar em um server component. Você vai passar tempo envolvendo coisas em arquivos "use client" apenas para usar um date picker ou uma biblioteca de animação. O ecossistema React está alcançando, mas a partir de 2024 ainda é irregular.
Honestamente, para um site de marketing simples ou um blog de conteúdo, você pode não precisar de RSCs. Se sua equipe está confortável com o pages router e seu desempenho é bom, fazer upgrade apenas para suporte a RSC não vale a dor. Já desaconselhei clientes a migrar mais de uma vez.
Conselhos Práticos para Adotar RSCs em um Projeto Existente
Se você está movendo um app Next.js existente para o diretório app/, aqui está a ordem que eu seguiria:
- Comece com componentes folha. Componentes que exibem dados mas não lidam com interação são as vitórias mais fáceis. Faça-os ser componentes de servidor primeiro.
- Identifique sua superfície de interatividade real. Geralmente é menor do que você pensa. Formulários, modais, dropdowns. Esse é seu território de
"use client". - Empurre `"use client"` o máximo possível para baixo. O botão que envia um formulário deve ser um componente cliente. O layout do formulário ao seu redor provavelmente não precisa ser.
- Faça auditoria de seu bundle com [@next/bundle-analyzer](https://www.npmjs.com/package/@next/bundle-analyzer). Execute antes e depois. Se você não está vendo redução significativa de bundle, você provavelmente ainda está enviando muito para o cliente.
- Não compartilhe módulos apenas de servidor. Instale server-only do npm e importe no topo de qualquer módulo que nunca deve alcançar o navegador. Vai lançar um erro no build se algo tentar importá-lo client-side.
O pacote server-only é uma coisa pequena, mas nos salvou de um cenário de vazamento de dados bem constrangedor em um projeto de cliente de saúde. Um desenvolvedor acidentalmente importou um utilitário de banco de dados em um componente que depois foi marcado "use client". O pacote detectou no build time. Use.
FAQ
React Server Components são a mesma coisa que SSR?
Não. SSR (server-side rendering) renderiza componentes para HTML no servidor, mas ainda envia o JavaScript do componente para o cliente para hidratação. RSCs renderizam no servidor e nunca enviam seu JavaScript para o navegador. SSR e RSCs podem trabalhar juntos, e no diretório app/ do Next.js, trabalham, mas resolvem problemas diferentes.
Eu preciso do Next.js para usar React Server Components?
Tecnicamente não, mas na prática sim para a maioria das equipes. RSCs requerem um framework que lide com a infraestrutura de servidor, roteamento e o pipeline de payload RSC. Next.js 13+ com o diretório app/ é a opção mais pronta para produção agora. Remix tem um modelo diferente. Construir seu próprio setup é possível, mas não é um bom uso do seu tempo a menos que você esteja construindo um framework você mesmo.
Posso misturar componentes de servidor e cliente na mesma página?
Sim, e esse é o ponto todo. Uma página pode ser um componente de servidor (busca dados, nenhum JS enviado), conter um componente cliente para um input de busca, que contém componentes de servidor como filhos passados via prop children. A árvore se entrelaça. Apenas lembre-se: componentes de servidor podem renderizar componentes cliente, mas componentes cliente não podem renderizar componentes de servidor diretamente.
O que acontece com meus hooks customizados existentes?
Hooks customizados que usam useState, useEffect ou APIs de navegador só podem rodar em componentes cliente. Você não precisa reescrevê-los, apenas seja deliberado sobre quais componentes os usam. Se um hook envolve uma chamada de busca de dados, considere se esses dados poderiam ser buscados em um componente de servidor e passados como props. Geralmente podem, e você acaba com código mais simples.
Há um custo de desempenho ao formato de Payload RSC?
Pode haver, particularmente se você está passando grandes quantidades de dados através do payload. O RSC Payload não é a mesma coisa que JSON, é um formato customizado, mas ainda adiciona bytes à sua resposta. Para a maioria dos apps, isso é negligenciável comparado à economia de bundle JS. Para apps com conjuntos de dados muito grandes sendo passados como props, perfile. Não assuma que RSCs sempre são menores na rede.
---
RSCs são um shift arquitetural genuíno, não apenas uma nova API. O modelo mental leva um tempo para se estabilizar. Dê esse tempo a ele. Construa algo pequeno com o diretório app/ antes de comprometer um grande projeto de cliente. Passei cerca de três semanas em experimentos antes de confiar em mim mesmo para enviar arquitetura baseada em RSC para produção, e eu escrevo React desde 2016.
O balanceio de mão vai continuar de pessoas que não construíram nada real com isso. Agora pelo menos você sabe o suficiente para notar a diferença.
