Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Busque dados em um Server Component e passe-os para um Client Component como dados de fallback para o SWR. Isso oferece conteúdo instantâneo renderizado no servidor com revalidação no lado do cliente - o melhor dos dois mundos.
// app/users/page.tsx (Server Component)
import { UserList } from "./user-list";
async function getUsers() {
const res = await fetch("https://api.example.com/users", {
next: { revalidate: 60 },
});
return res.json();
}
export default async function UsersPage() {
const users = await getUsers();
return <UserList fallbackData={users} />;
}// app/users/user-list.tsx (Client Component)
"use client";
import useSWR from "swr";
interface User {
id: string;
name: string;
}
const fetcher = (url: string) => fetch(url).then((r) => r.json());
export function UserList({ fallbackData }: { fallbackData: User[] }) {
const { data: users } = useSWR<User[]>("/api/users", fetcher, {
fallbackData,
revalidateOnMount: true, // Re-busca ao montar para obter dados recentes
});
return (
<ul>
{users?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}// app/dashboard/page.tsx (Server Component)
import { SWRProvider } from "./swr-provider";
import { DashboardStats } from "./dashboard-stats";
import { RecentOrders } from "./recent-orders";
async function fetchDashboardData() {
const [stats, orders] = await Promise.all([
fetch("https://api.example.com/stats").then((r) => r.json()),
fetch("https://api.example.com/orders?limit=10").then((r) => r.json()),
]);
return { stats, orders };
}
export default async function DashboardPage() {
const { stats, orders } = await fetchDashboardData();
return (
<SWRProvider
fallback={{
"/api/stats": stats,
"/api/orders?limit=10": orders,
}}
>
<h1>Dashboard</h1>
<DashboardStats />
<RecentOrders />
</SWRProvider>
);
}// app/dashboard/swr-provider.tsx
"use client";
import { SWRConfig } from "swr";
export function SWRProvider({
children,
fallback,
}: {
children: React.ReactNode;
fallback: Record<string, any>;
}) {
return (
<SWRConfig
value={{
fallback,
fetcher: (url: string) => fetch(url).then((r) => r.json()),
}}
>
{children}
</SWRConfig>
);
}// app/dashboard/dashboard-stats.tsx
"use client";
import useSWR from "swr";
interface Stats {
revenue: number;
orders: number;
customers: number;
}
export function DashboardStats() {
// Dados instantaneamente disponíveis do fallback do servidor
const { data: stats } = useSWR<Stats>("/api/stats", {
refreshInterval: 30000, // Manter estatísticas atualizadas
});
return (
<div className="grid grid-cols-3 gap-4">
<div>Receita: ${stats?.revenue.toLocaleString()}</div>
<div>Pedidos: {stats?.orders}</div>
<div>Clientes: {stats?.customers}</div>
</div>
);
}// app/dashboard/recent-orders.tsx
"use client";
import useSWR from "swr";
interface Order {
id: string;
customer: string;
total: number;
status: string;
}
export function RecentOrders() {
const { data: orders } = useSWR<Order[]>("/api/orders?limit=10");
return (
<table>
<thead>
<tr>
<th>Pedido</th>
<th>Cliente</th>
<th>Total</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{orders?.map((order) => (
<tr key={order.id}>
<td>{order.id}</td>
<td>{order.customer}</td>
<td>${order.total}</td>
<td>{order.status}</td>
</tr>
))}
</tbody>
</table>
);
}SWRConfig.fallback.fallback do SWRConfig é um mapa de { [chave]: dados } que pré-popula o cache do SWR no cliente.useSWR é montado com dados de fallback correspondentes, ele renderiza imediatamente sem um estado de carregamento.revalidateOnMount: false), garantindo que os dados permaneçam atualizados.preload também pode ser usada para iniciar a busca antes que um componente seja montado.Pré-carregamento em Server Component:
// app/products/[id]/page.tsx
import { preload } from "swr";
import { ProductDetail } from "./product-detail";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
export default function ProductPage({ params }: { params: { id: string } }) {
// Inicia a busca imediatamente
preload(`/api/products/${params.id}`, fetcher);
return <ProductDetail id={params.id} />;
}Fallback por página sem provedor global:
"use client";
import useSWR from "swr";
export function UserCard({ fallbackData }: { fallbackData: User }) {
const { data } = useSWR("/api/me", fetcher, {
fallbackData, // Fallback por hook
revalidateOnMount: false, // Confia nos dados do servidor, pula a revalidação inicial
});
return <div>{data?.name}</div>;
}Streaming com Suspense:
// Server Component
import { Suspense } from "react";
export default function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<StatsSkeleton />}>
<StatsLoader />
</Suspense>
</div>
);
}
async function StatsLoader() {
const stats = await fetch("https://api.example.com/stats").then((r) => r.json());
return <StatsClient fallbackData={stats} />;
}fallback em SWRConfig é tipada como Record<string, any>. Não há verificação em tempo de compilação de que as chaves correspondam às suas chaves useSWR.type FallbackMap = {
"/api/stats": Stats;
"/api/orders?limit=10": Order[];
};
function TypedSWRProvider<T extends Record<string, unknown>>({
fallback,
children,
}: {
fallback: T;
children: React.ReactNode;
}) {
return <SWRConfig value={{ fallback }}>{children}</SWRConfig>;
}fallback devem corresponder exatamente às chaves usadas em useSWR. Uma incompatibilidade significa que os dados de fallback são ignorados silenciosamente e um estado de carregamento aparece.revalidateOnMount: true (o padrão quando fallbackData é fornecido e nenhum revalidateIfStale é definido) causa uma re-busca imediata. Defina como false se os dados do servidor forem recentes o suficiente.useSWR diretamente em Server Components. Os hooks SWR são apenas para cliente. Server Components devem usar fetch diretamente ou uma camada de dados do lado do servidor.fallback em SWRConfig, os dados estão disponíveis para todos os hooks useSWR aninhados. Tenha cuidado com colisões de chaves entre componentes não relacionados.| Abordagem | Prós | Contras |
|---|---|---|
| Fallback do SWRConfig | Cache pré-populado, renderização instantânea | Chaves devem corresponder exatamente, sem segurança de tipo no fallback |
| fallbackData por hook | Explícito, no nível do componente | Precisa passar props do servidor |
| Busca apenas no servidor (sem SWR) | Mais simples, sem JS no cliente | Sem revalidação no lado do cliente |
| Hidratação do React Query | Desidratação/hidratação integrada | Biblioteca diferente, mais configuração |
A prop fallback é um mapa { [chave]: dados } que pré-popula o cache do SWR no cliente. Quando um hook useSWR é montado com uma chave correspondente, ele renderiza imediatamente sem um estado de carregamento, e depois revalida em segundo plano.
fallbackData é definido por hook useSWR como uma prop: useSWR(key, fetcher, { fallbackData }).fallback no SWRConfig fornece dados para todos os hooks aninhados através de um mapa chave-valor.fallbackData para componentes individuais; use fallback para pré-popular a página inteira.Os dados de fallback são ignorados silenciosamente. O SWR exibe um estado de carregamento em vez de conteúdo instantâneo. Sempre certifique-se de que as chaves no seu mapa fallback correspondam exatamente às chaves usadas nas chamadas useSWR.
Não. Os hooks SWR são apenas para cliente. Server Components devem usar fetch diretamente ou uma camada de dados do lado do servidor, e então passar os dados como props ou via SWRConfig fallback para Client Components.
Por padrão, sim (revalidateOnMount: true). Isso garante que os dados permaneçam atualizados. Defina revalidateOnMount: false se os dados do servidor forem recentes o suficiente e você quiser pular a busca inicial no lado do cliente.
Passe dados buscados no servidor através de SWRConfig fallback ou fallbackData. Isso garante que o HTML renderizado no servidor corresponda à renderização inicial do cliente, evitando erros de hidratação.
Os dados serializados de Server Components devem ser seguros para JSON. Datas, Maps, Sets e instâncias de classe não sobreviverão à fronteira. Converta-os para objetos simples ou strings antes de passar.
import { preload } from "swr";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
export default function Page({ params }: { params: { id: string } }) {
preload(`/api/products/${params.id}`, fetcher);
return <ProductDetail id={params.id} />;
}A prop fallback é tipada como Record<string, any> -- não há verificação em tempo de compilação de que as chaves correspondam às chaves useSWR. Para tipagem mais forte, crie um wrapper tipado:
type FallbackMap = {
"/api/stats": Stats;
"/api/orders?limit=10": Order[];
};
function TypedSWRProvider<T extends Record<string, unknown>>({
fallback,
children,
}: {
fallback: T;
children: React.ReactNode;
}) {
return <SWRConfig value={{ fallback }}>{children}</SWRConfig>;
}Use <Suspense> em torno de um Server Component assíncrono que busca dados e os passa como fallbackData para um Client Component com useSWR. O servidor transmite o HTML à medida que os dados ficam disponíveis.
Todos os hooks useSWR aninhados que compartilham a mesma chave recebem os mesmos dados de fallback. Tenha cuidado para que componentes não relacionados não usem acidentalmente a mesma chave, o que faria com que compartilhassem dados desatualizados ou incorretos.
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥