//
Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
// app/page.tsx (Server Component -- o padrão no Next.js App Router)
import { db } from "@/lib/db";
import ClientCounter from "./ClientCounter";
export default async function DashboardPage() {
// Acesso direto ao banco de dados -- este código nunca chega ao navegador
const stats = await db.query("SELECT count(*) FROM orders");
return (
<main>
<h1>Dashboard</h1>
<p>Total de pedidos: {stats.count}</p>
{/* Transfere para um Client Component para interatividade */}
<ClientCounter initialCount={stats.count} />
</main>
);
}// app/ClientCounter.tsx
"use client";
import { useState } from "react";
export default function ClientCounter({ initialCount }: { initialCount: number }) {
const [count, setCount] = useState(initialCount);
return <button onClick={() => setCount(c => c + 1)}>Contagem: {count}</button>;
}Quando usar isso: Use Server Components sempre que um componente precisar apenas ler dados e renderizar HTML -- sem manipuladores de eventos, sem estado, sem APIs do navegador.
// Uma página de catálogo de produtos misturando preocupações de servidor e cliente
// app/products/page.tsx (Server Component)
import { Suspense } from "react";
import { getProducts, getCategories } from "@/lib/api";
import ProductGrid from "./ProductGrid";
import CategoryFilter from "./CategoryFilter";
export default async function ProductsPage() {
const categories = await getCategories();
return (
<div className="flex gap-6">
{/* Client Component para filtragem interativa */}
<CategoryFilter categories={categories} />
{/* Server Component com streaming */}
<Suspense fallback={<p>Carregando produtos...</p>}>
<ProductList />
</Suspense>
</div>
);
}
async function ProductList() {
const products = await getProducts();
// ProductGrid é um componente "use client" que recebe props serializáveis
return <ProductGrid products={products} />;
}// app/products/CategoryFilter.tsx
"use client";
import { useState, useTransition } from "react";
import { useRouter } from "next/navigation";
type Props = { categories: { id: string; name: string }[] };
export default function CategoryFilter({ categories }: Props) {
const [selected, setSelected] = useState<string | null>(null);
const [isPending, startTransition] = useTransition();
const router = useRouter();
function handleSelect(id: string) {
setSelected(id);
startTransition(() => {
router.push(`/products?category=${id}`);
});
}
return (
<aside>
<h2>Categorias</h2>
<ul>
{categories.map((c) => (
<li key={c.id}>
<button
onClick={() => handleSelect(c.id)}
className={selected === c.id ? "font-bold" : ""}
>
{c.name}
</button>
</li>
))}
</ul>
{isPending && <p>Filtrando...</p>}
</aside>
);
}// app/products/ProductGrid.tsx
"use client";
type Product = { id: string; name: string; price: number };
export default function ProductGrid({ products }: { products: Product[] }) {
return (
<div className="grid grid-cols-3 gap-4">
{products.map((p) => (
<div key={p.id} className="border p-4 rounded">
<h3>{p.name}</h3>
<p>${p.price.toFixed(2)}</p>
<button onClick={() => alert(`Adicionado ${p.name}`)}>Adicionar ao carrinho</button>
</div>
))}
</div>
);
}O que isso demonstra:
Suspense transmitindo um server component lento"use client""use client" no topo para optar pela renderização no lado do cliente.importar Client Components, mas Client Components não podem importar Server Components. Em vez disso, passe Server Components como children ou outras props JSX.Map, Set, FormData, typed arrays, Promise (com use()), server actions e elementos JSX. Funções (exceto server actions), classes e nós DOM não são serializáveis.async -- eles podem usar await diretamente no corpo da função. Isso não é permitido em Client Components.Padrões de busca de dados assíncronos:
// Padrão 1: Await de nível superior
async function UserProfile({ userId }: { userId: string }) {
const user = await fetchUser(userId);
return <h1>{user.name}</h1>;
}
// Padrão 2: Busca de dados paralela
async function Dashboard() {
const [users, posts, stats] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchStats(),
]);
return (
<>
<UserList users={users} />
<PostFeed posts={posts} />
<StatsPanel stats={stats} />
</>
);
}
// Padrão 3: Passar promessa para o cliente (adiar resolução)
async function Page() {
const dataPromise = fetchSlowData(); // NÃO await
return <ClientChart dataPromise={dataPromise} />;
}Padrão de composição -- passando Server Components como children:
// Isso funciona porque children é JSX já renderizado, não um import
"use client";
export function ClientLayout({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(true);
return <div className={open ? "expanded" : "collapsed"}>{children}</div>;
}Promise<JSX.Element>. O TypeScript lida com isso automaticamente com os tipos do React 19.React.ReactNode para a prop children quando um Client Component envolve a saída de um Server Component.importar um módulo de Server Component. Correção: Passe o Server Component como children ou outra prop JSX em vez de importá-lo.useState, useEffect, useRef, etc. são apenas para o cliente. Correção: Mova a lógica interativa para um componente "use client"."use server") em vez disso, que o React serializa como uma referência RPC.useEffect ou APIs do navegador falharão em Server Components. Correção: Importe-as apenas dentro de arquivos "use client" ou use um wrapper.window, document, localStorage, etc. não existem no servidor. Correção: Proteja o código exclusivo do navegador com "use client".| Abordagem | Quando escolher |
|---|---|
| Server Components | UI somente leitura, busca de dados, dependências grandes que você quer fora do bundle |
| Client Components | UI interativa com estado, efeitos ou APIs do navegador |
| Renderização do lado do servidor (SSR) sem RSC | Aplicativos pré-React 19, frameworks que ainda não suportam RSC |
| Geração de Site Estático (SSG) | Conteúdo que raramente muda e pode ser construído no momento da implantação |
| Rotas de API + fetch do cliente | Quando você precisa de controle granular sobre o cache e a forma dos dados |
"use client" no topo para optar pela renderização no lado do clientechildren ou outras props JSX para Client ComponentsMap, Set, FormData, typed arraysPromise (consumido com use()) e server actions também são serializáveisuseState, useEffect, useRef, etc. são apenas para o clienteawait diretamente no corpo da função em vez disso"use client"async function Dashboard() {
const [users, posts, stats] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchStats(),
]);
return <>{/* renderiza dados */}</>;
}<Suspense> para streaming -- o fallback é exibido enquanto o componente resolveuseEffect, useState, ou APIs do navegador (window, document) falharão em Server Components"use client" ou crie um wrapper de componente cliente fino// Server Component -- NÃO await
async function Page() {
const dataPromise = fetchSlowData();
return <ClientChart dataPromise={dataPromise} />;
}O componente cliente usa use(dataPromise) dentro de um limite <Suspense> para resolvê-la.
Promise<JSX.Element> -- TypeScript lida com isso automaticamente com os tipos do React 19React.ReactNode para a prop children quando um Client Component envolve a saída de um Server Component"use client";
export function ClientLayout({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(true);
return <div className={open ? "expanded" : "collapsed"}>{children}</div>;
}O children é JSX já renderizado de um Server Component, não um import.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥