Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Ative a opção suspense em useSWR para integrar com os limites do React Suspense. Quando o suspense está ativo, SWR lança uma promessa durante o carregamento, permitindo que <Suspense> gerencie a UI de fallback.
"use client";
import { Suspense } from "react";
import useSWR from "swr";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
function UserName({ id }: { id: string }) {
// Com suspense: true, data é garantido como definido
const { data } = useSWR(`/api/users/${id}`, fetcher, { suspense: true });
return <span>{data.name}</span>;
}
export default function Page() {
return (
<Suspense fallback={<div>Carregando usuário...</div>}>
<UserName id="1" />
</Suspense>
);
}"use client";
import { Suspense } from "react";
import useSWR, { SWRConfig } from "swr";
interface Post {
id: string;
title: string;
body: string;
}
interface Comment {
id: string;
text: string;
author: string;
}
const fetcher = (url: string) => fetch(url).then((r) => r.json());
function PostContent({ postId }: { postId: string }) {
const { data: post } = useSWR<Post>(`/api/posts/${postId}`, fetcher, {
suspense: true,
});
return (
<article>
<h1>{post!.title}</h1>
<p>{post!.body}</p>
</article>
);
}
function PostComments({ postId }: { postId: string }) {
const { data: comments } = useSWR<Comment[]>(
`/api/posts/${postId}/comments`,
fetcher,
{ suspense: true }
);
return (
<ul>
{comments!.map((c) => (
<li key={c.id}>
<strong>{c.author}</strong>: {c.text}
</li>
))}
</ul>
);
}
export default function PostPage({ postId }: { postId: string }) {
return (
<SWRConfig value={{ suspense: true }}>
<Suspense fallback={<div>Carregando post...</div>}>
<PostContent postId={postId} />
</Suspense>
<Suspense fallback={<div>Carregando comentários...</div>}>
<PostComments postId={postId} />
</Suspense>
</SWRConfig>
);
}suspense: true, SWR lança uma promessa quando os dados ainda não estão disponíveis. O limite <Suspense> do React captura isso e renderiza o fallback.data é garantido como definido (não undefined).useSWR dentro do mesmo limite <Suspense> acionarão buscas paralelas, mas o limite espera por todas elas.<Suspense> separados em torno de cada componente dependente de dados permitem estados de carregamento independentes e streaming.Suspense global via SWRConfig:
<SWRConfig value={{ suspense: true }}>
<Suspense fallback={<Loading />}>
{children}
</Suspense>
</SWRConfig>Suspense aninhado para carregamento progressivo:
<Suspense fallback={<HeaderSkeleton />}>
<Header />
<Suspense fallback={<ContentSkeleton />}>
<MainContent />
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
</Suspense>
</Suspense>Combinado com ErrorBoundary:
import { ErrorBoundary } from "react-error-boundary";
<ErrorBoundary fallback={<div>Algo deu errado</div>}>
<Suspense fallback={<div>Carregando...</div>}>
<DataComponent />
</Suspense>
</ErrorBoundary>suspense: true, data ainda é tipado como Data | undefined por padrão. Use uma asserção não nula ou um cast quando você souber que o suspense garante a presença dos dados.function useSuspenseSWR<T>(key: string, fetcher: (url: string) => Promise<T>) {
const result = useSWR<T>(key, fetcher, { suspense: true });
return { ...result, data: result.data as T };
}
// data é tipado como User, não User | undefined
const { data } = useSuspenseSWR<User>("/api/me", fetcher);useTransition com SWR podem ter casos extremos.fallback em SWRConfig para evitar dessincronizações de hidratação entre o servidor e o cliente.isLoading e isValidating têm semânticas diferentes no modo suspense. O componente simplesmente não renderiza enquanto carrega, então você nunca vê isLoading: true dentro do componente.suspense: true sem um limite <Suspense>, o React lançará um erro para o Error Boundary mais próximo ou travará o aplicativo.null) desativam o comportamento de suspense para esse hook. O componente renderizará com data: undefined.| Abordagem | Prós | Contras |
|---|---|---|
| Modo suspense do SWR | Estados de carregamento limpos, composable | Complexidade SSR, necessidade de estreitamento de tipo |
| Verificações manuais de isLoading | Controle total, explícito | Código repetitivo de UI de carregamento |
| React Server Components | Nenhum estado de carregamento do cliente necessário | Não pode usar hooks, sem atualizações em tempo real |
| Hook use() (React 19) | Desembrulhamento nativo de promessa | Experimental, API diferente |
Com suspense: true, SWR lança uma promessa quando os dados ainda não estão disponíveis. O limite <Suspense> do React captura essa promessa, renderiza o fallback e re-renderiza o componente assim que a promessa é resolvida.
Sim, em tempo de renderização data é garantido como disponível porque o componente só renderiza após a promessa ser resolvida. No entanto, o TypeScript ainda o tipa como Data | undefined por padrão. Use uma asserção não nula ou um hook wrapper para estreitar o tipo.
O React lançará a promessa para cima. Se não houver um limite <Suspense>, ela atingirá o Error Boundary mais próximo ou travará o aplicativo inteiramente.
<SWRConfig value={{ suspense: true }}>
<Suspense fallback={<Loading />}>
{children}
</Suspense>
</SWRConfig>Sim. Múltiplas chamadas useSWR dentro do mesmo limite <Suspense> acionam buscas paralelas. O limite espera por todas elas antes de renderizar.
Não. Apenas o carregamento inicial suspende. Revalidações em segundo plano atualizam os dados silenciosamente sem acionar o fallback Suspense novamente.
Erros no modo suspense são lançados durante a renderização, então eles são capturados pelo Error Boundary mais próximo. Envolva seu <Suspense> dentro de um <ErrorBoundary>:
<ErrorBoundary fallback={<div>Erro</div>}>
<Suspense fallback={<div>Carregando...</div>}>
<DataComponent />
</Suspense>
</ErrorBoundary>SWR recorre à busca no lado do cliente durante o SSR. Você precisa pré-popular o cache com fallback em SWRConfig para evitar dessincronizações de hidratação entre servidor e cliente.
function useSuspenseSWR<T>(key: string, fetcher: (url: string) => Promise<T>) {
const result = useSWR<T>(key, fetcher, { suspense: true });
return { ...result, data: result.data as T };
}
// data é tipado como T, não T | undefinedChaves condicionais (null) desativam o comportamento de suspense para esse hook. O componente renderiza imediatamente com data: undefined em vez de suspender.
Envolva cada seção dependente de dados em seu próprio limite <Suspense>. Isso permite estados de carregamento independentes e streaming, para que seções mais rápidas renderizem sem esperar por seções mais lentas.
Revisado por Chris St. John·Última atualização: 7 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥