Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Habilita la opción suspense en useSWR para integrarlo con los límites de React Suspense. Cuando suspense está activo, SWR lanza una promesa durante la carga, permitiendo que <Suspense> gestione la interfaz de respaldo.
"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 }) {
// Con suspense: true, data está garantizado como definido
const { data } = useSWR(`/api/users/${id}`, fetcher, { suspense: true });
return <span>{data.name}</span>;
}
export default function Page() {
return (
<Suspense fallback={<div>Cargando usuario...</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>Cargando publicación...</div>}>
<PostContent postId={postId} />
</Suspense>
<Suspense fallback={<div>Cargando comentarios...</div>}>
<PostComments postId={postId} />
</Suspense>
</SWRConfig>
);
}suspense: true, SWR lanza una promesa cuando los datos aún no están disponibles. El límite <Suspense> de React la captura y renderiza el respaldo.data está garantizado como definido (no undefined).useSWR dentro del mismo límite <Suspense> activan obtenciones en paralelo, pero el límite espera a que todas terminen.<Suspense> separados alrededor de cada componente dependiente de datos permiten estados de carga independientes y streaming.Suspense global mediante SWRConfig:
<SWRConfig value={{ suspense: true }}>
<Suspense fallback={<Loading />}>
{children}
</Suspense>
</SWRConfig>Suspense anidado para carga progresiva:
<Suspense fallback={<HeaderSkeleton />}>
<Header />
<Suspense fallback={<ContentSkeleton />}>
<MainContent />
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
</Suspense>
</Suspense>Combinado con ErrorBoundary:
import { ErrorBoundary } from "react-error-boundary";
<ErrorBoundary fallback={<div>Algo salió mal</div>}>
<Suspense fallback={<div>Cargando...</div>}>
<DataComponent />
</Suspense>
</ErrorBoundary>suspense: true, data sigue tipado como Data | undefined por defecto. Usa una aserción non-null o un cast cuando sepas que suspense garantiza la presencia de los datos.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 está tipado como User, no User | undefined
const { data } = useSuspenseSWR<User>("/api/me", fetcher);useTransition con SWR pueden tener casos límite.fallback en SWRConfig para evitar desincronizaciones de hidratación.isLoading e isValidating tienen semánticas distintas en modo suspense. El componente simplemente no se renderiza mientras carga, así que nunca verás isLoading: true dentro del componente.suspense: true sin un límite <Suspense>, React lanzará un error hasta el Error Boundary más cercano o hará fallar la aplicación.null) desactivan el comportamiento de suspense para ese hook. El componente se renderizará con data: undefined.| Enfoque | Ventajas | Desventajas |
|---|---|---|
| Modo suspense de SWR | Estados de carga limpios, componible | Complejidad con SSR, requiere restringir tipos |
| Comprobaciones manuales de isLoading | Control total, explícito | Código repetitivo de interfaz de carga |
| React Server Components | No requiere estado de carga en el cliente | No puedes usar hooks, sin actualizaciones en tiempo real |
| Hook use() (React 19) | Desenvoltura nativa de promesas | Experimental, API distinta |
Con suspense: true, SWR lanza una promesa cuando los datos aún no están disponibles. El límite <Suspense> de React captura esa promesa, renderiza el respaldo y vuelve a renderizar el componente una vez que la promesa se resuelve.
Sí, en tiempo de renderizado data está garantizado como disponible porque el componente solo se renderiza después de que la promesa se resuelve. Sin embargo, TypeScript sigue tipándolo como Data | undefined por defecto. Usa una aserción non-null o un hook envoltorio para restringir el tipo.
React lanzará la promesa hacia arriba. Si no hay un límite <Suspense>, llegará al Error Boundary más cercano o hará fallar la aplicación por completo.
<SWRConfig value={{ suspense: true }}>
<Suspense fallback={<Loading />}>
{children}
</Suspense>
</SWRConfig>Sí. Varias llamadas a useSWR dentro del mismo límite <Suspense> activan obtenciones en paralelo. El límite espera a que todas terminen antes de renderizar.
No. Solo la carga inicial suspende. Las revalidaciones en segundo plano actualizan los datos en silencio sin volver a activar el respaldo de Suspense.
Los errores en modo suspense se lanzan durante el renderizado, por lo que los captura el Error Boundary más cercano. Envuelve tu <Suspense> dentro de un <ErrorBoundary>:
<ErrorBoundary fallback={<div>Error</div>}>
<Suspense fallback={<div>Cargando...</div>}>
<DataComponent />
</Suspense>
</ErrorBoundary>SWR recurre a la obtención en el cliente durante SSR. Necesitas prepoblar la caché con fallback en SWRConfig para evitar desincronizaciones de hidratación entre servidor y 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 está tipado como T, no T | undefinedLas claves condicionales (null) desactivan el comportamiento de suspense para ese hook. El componente se renderiza de inmediato con data: undefined en lugar de suspender.
Envuelve cada sección dependiente de datos en su propio límite <Suspense>. Esto permite estados de carga independientes y streaming, de modo que las secciones más rápidas se renderizan sin esperar a las más lentas.
Revisado por Chris St. John·Última actualización: 7 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥