Capítulo 80 de 456

Server and Client Boundary

Core Idea

Explica onde Server e Client Components rodam de fato, o que atravessa a fronteira entre eles (código via imports, dados via props serializáveis), e as regras práticas para compor os dois num mesmo tree.

Key Concepts

  • RSC Payload: descrição serializada da UI produzida pelo server graph, contendo referências aos Client Components e seus props serializados.
  • Server Component: roda só no servidor (nunca no browser); seu código nunca é enviado ao bundle cliente.
  • Client Component: roda no servidor (para gerar HTML inicial) E no browser (hidratação e re-renders); indicado por 'use client'.
  • Módulo compartilhado: um módulo usado em ambos os graphs é compilado separadamente para cada ambiente pelo Next.js.
  • use (React): hook que permite a um Client Component ler uma promise passada como prop de um Server Component, streamando dado sem fetch adicional no cliente; enquanto pendente, o <Suspense> mais próximo mostra o fallback.
  • Fetch memoization: requisições fetch idênticas são memoizadas durante um render de servidor.
  • Owner vs. parent: owner é quem contém o JSX de um filho no código-fonte; parent é quem contém o filho na árvore renderizada — um Client Component pode ser parent de um Server Component sem ser seu owner (via children), preservando o Server Component rodando no servidor.
  • Regra de cruzamento de código: o que um Client Component importa entra no client bundle.
  • Regra de cruzamento de dados: props devem ser serializáveis; funções comuns (como onClick) não cruzam — só Server Functions ('use server') cruzam, como referência.

Code Examples

import { Cart } from '@/app/ui/cart'
import { Modal } from '@/app/ui/modal'

// Page and Cart are Server Components. Modal is a Client Component
export default function Page() {
  return (
    <Modal title={<div>Your cart</div>}>
      <Cart />
    </Modal>
  )
}
'use client'
import { useState, type ReactNode } from 'react'

export function Modal({ title, children }: { title: ReactNode; children: ReactNode }) {
  const [open, setOpen] = useState(true)
  if (!open) return null
  return (
    <div role="dialog">
      <header>{title}<button onClick={() => setOpen(false)}>Close</button></header>
      {children}
    </div>
  )
}
  • O que demonstra: Cart (Server Component) é passado como children para Modal (Client Component) — Cart roda no servidor e Modal só recebe seu output renderizado, nunca importa seu código.

Anti-patterns

  • Passar uma função comum como prop de Server pra Client Component: lança erro — apenas 'use server' functions cruzam a fronteira, como referência.
  • Expor subcomponentes de compound component como propriedade estática (Menu.Item) quando o Server Component importa um Client Component: o Server Component recebe uma referência cliente em vez da função, então Menu.Item vira undefined e React lança "Element type is invalid". Use named exports em vez de static properties para consumo a partir de Server Components.
  • Mutar DOM de Server Component diretamente: dessincroniza o DOM da árvore de componentes React — para atualizar output de Server Component, renderize-o de novo no servidor.
  • Adicionar 'use client' em todo arquivo de uma subárvore: desnecessário — a diretiva só precisa estar na entrada da subárvore cliente; todo módulo importado a partir dali já entra no client graph.

Key Takeaways

  1. "Server-rendered" descreve como o HTML foi produzido (SSG/ISR/SSR); "Server Component" descreve onde o código roda e se vai ao browser — são conceitos ortogonais.
  2. Um Client Component também roda no servidor na primeira renderização (produz HTML), mas continua sendo Client Component.
  3. Use children/props de React element para deixar um Server Component aninhado dentro de um Client Component sem que o Client Component precise importar seu código.
  4. Comportamento nativo de HTML (<details>, <form action={serverFunction}>, <video controls>) dá interatividade sem precisar de Client Component.
  5. Para não poluir um componente compartilhado com 'use client', crie um wrapper Client Component que o importa e coloque a diretiva só no wrapper.

Connects To

  • Server Actions (ch079): Server Functions são o único tipo de função que cruza a fronteira servidor→cliente como referência.
  • Rendering Philosophy (ch075): contexto de quando um componente renderiza (build time vs. request time), complementar a onde ele roda.
  • Data Security guide: cuidado com o que é passado via props de Server para Client Component (serialização expõe dado ao browser).