R
Interview Deckreact · next.js · senior/staff
0·0·122
Avançado

React Server Components (RSC)

O que são RSC, quando usar Server vs Client Components, e como pensar a fronteira.

React Server Components rodam exclusivamente no servidor: sem hydration, sem JS enviado ao cliente, acesso direto a banco/filesystem/variáveis de ambiente. Client Components ('use client') têm interatividade, hooks de estado e efeitos. No Next.js App Router, todos os componentes são Server por padrão. A fronteira server/client é onde você adiciona 'use client'.

Problema
Marcar tudo como 'use client' por hábito derrota o propósito dos RSC. Ou o oposto: tentar usar useState em Server Components e não entender o erro.
Solução
Regra: mova 'use client' para as folhas da árvore. Componentes de layout, listas, tabelas — Server. Componentes com interação (formulários, toggles, modais) — Client. Server Components podem passar dados como props para Client Components, mas não o contrário.
Tip
Server Components não têm: useState, useEffect, event handlers, Browser APIs. Client Components têm tudo isso. Dúvida: o componente precisa reagir a input do usuário ou mudança de estado no browser? 'use client'. Só renderiza dados estáticos? Server.
// ✅ Server Component — sem JS no cliente, fetch direto
// app/products/page.tsx (Server Component por default)
async function ProductsPage() {
  // Acesso direto ao banco — sem API, sem useEffect
  const products = await db.product.findMany({ where: { active: true } })

  return (
    <main>
      <h1>Produtos</h1>
      {/* ProductCard é Server Component — zero hydration */}
      {products.map(p => <ProductCard key={p.id} product={p} />)}

      {/* AddToCartButton precisa de estado — é Client */}
      <AddToCartButton productId={products[0].id} />
    </main>
  )
}

// ✅ Client Component na folha da árvore
// components/AddToCartButton.tsx
'use client'
import { useState } from 'react'

export function AddToCartButton({ productId }: { productId: string }) {
  const [added, setAdded] = useState(false)

  return (
    <button onClick={() => {
      addToCart(productId)
      setAdded(true)
    }}>
      {added ? '✓ Adicionado' : 'Adicionar ao carrinho'}
    </button>
  )
}

// ✅ Passando Server Component como children para Client
function ClientLayout({ children }: { children: React.ReactNode }) {
  'use client'
  const [open, setOpen] = useState(false)
  return <div>{open && children}</div>
}
// children pode ser um Server Component!
Q.Qual a vantagem real dos Server Components?
A.Zero JS enviado ao cliente para componentes puramente de apresentação. Acesso direto a banco sem API intermediária. Fetch de dados no servidor = sem loading state, sem useEffect, sem race conditions. Secrets do servidor nunca expostos. Bundle menor = melhor performance.
Q.Posso importar um Server Component dentro de um 'use client'?
A.Não diretamente — o boundary 'use client' transforma tudo abaixo em client. Mas você pode passar Server Components como children ou props para Client Components: `<ClientWrapper>{children}</ClientWrapper>` onde children é um Server Component. O padrão correto é passar como prop, não importar.
Q.Como fazer fetch de dados em RSC?
A.Diretamente no componente com async/await — Server Components podem ser async: `async function Page() { const data = await db.query(...); return <List data={data} /> }`. No Next.js, o fetch é automaticamente deduplicado e cacheado. Para revalidação: `fetch(url, { next: { revalidate: 60 } })` ou `revalidatePath()`.
82/122← →