Instalación y configuración de SWR
Receta
Instala SWR, envuelve tu app con SWRConfig y define valores predeterminados globales para que cada llamada a useSWR herede un fetcher compartido y opciones comunes.
npm install swr// app/providers.tsx
"use client";
import { SWRConfig } from "swr";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export function SWRProvider({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher,
revalidateOnFocus: true,
dedupingInterval: 2000,
}}
>
{children}
</SWRConfig>
);
}// app/layout.tsx
import { SWRProvider } from "./providers";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<SWRProvider>{children}</SWRProvider>
</body>
</html>
);
}Ejemplo funcional
"use client";
import useSWR from "swr";
function UserProfile({ userId }: { userId: string }) {
// el fetcher se hereda de SWRConfig
const { data, error, isLoading } = useSWR(`/api/users/${userId}`);
if (isLoading) return <div>Cargando...</div>;
if (error) return <div>Error al cargar</div>;
return <div>¡Hola, {data.name}!</div>;
}Profundización
Cómo funciona
SWRConfigusa React Context internamente para propagar valores de configuración por el árbol de componentes.- Cualquier llamada a
useSWRsin unfetcherexplícito recurrirá al fetcher del proveedorSWRConfigmás cercano. - Se pueden anidar varios proveedores
SWRConfig; los valores internos se fusionan con los externos y los sobrescriben. dedupingIntervalevita solicitudes duplicadas a la misma clave dentro de los milisegundos especificados.revalidateOnFocusprovoca una revalidación en segundo plano cuando la pestaña del navegador recupera el foco.
Variaciones
Fetcher personalizado con cabeceras:
const authedFetcher = (url: string) =>
fetch(url, {
headers: { Authorization: `Bearer ${getToken()}` },
}).then((res) => {
if (!res.ok) throw new Error("Error al obtener los datos");
return res.json();
});Sobrescritura de configuración anidada:
<SWRConfig value={{ fetcher: globalFetcher }}>
<SWRConfig value={{ refreshInterval: 3000 }}>
{/* Los componentes aquí obtienen globalFetcher + refresh de 3 s */}
</SWRConfig>
</SWRConfig>Configuración funcional (acceder al padre):
<SWRConfig
value={(parentConfig) => ({
...parentConfig,
refreshInterval: 5000,
})}
>
{children}
</SWRConfig>Notas de TypeScript
SWRConfigaceptavaluetipado comoPartial<SWRConfiguration>o una función que devuelve uno.- Importa
SWRConfigurationdesdeswrpara tipar objetos de configuración de forma explícita.
import type { SWRConfiguration } from "swr";
const config: SWRConfiguration = {
fetcher: (url: string) => fetch(url).then((r) => r.json()),
revalidateOnFocus: false,
};Errores comunes
- Olvidar añadir
"use client"en el archivo del proveedor en Next.js App Router provocará un error en tiempo de ejecución porqueSWRConfigusa React Context. - Si tu fetcher lanza errores en respuestas no 2xx, SWR lo trata como un error. Si no lanza,
errorsiempre seráundefined, incluso en 404. dedupingIntervalno es lo mismo que el almacenamiento en caché. Solo deduplica solicitudes en curso dentro de la ventana del intervalo.- Definir
refreshIntervala nivel global se aplica a cada hook. Prefiere configurarlo por hook a menos que realmente necesites polling global.
Alternativas
| Enfoque | Ventajas | Desventajas |
|---|---|---|
| SWRConfig global | Configuración única, valores predeterminados consistentes | Todos los hooks comparten la config; puede ser demasiado amplio |
| Config por hook | Control detallado por consulta | Declaraciones repetitivas del fetcher |
| Wrapper de hook personalizado | Lógica centralizada con flexibilidad | Capa de abstracción adicional |
FAQs
¿Por qué el archivo del proveedor SWRConfig necesita "use client" en Next.js App Router?
SWRConfig usa React Context internamente, que es una API del lado del cliente. Sin "use client", Next.js trata el archivo como un Server Component y lanza un error en tiempo de ejecución cuando se usa Context.
¿Qué hace realmente la opción dedupingInterval?
- Deduplica solicitudes en curso a la misma clave dentro de la ventana de milisegundos especificada (predeterminado 2000 ms).
- Si dos componentes se montan y llaman a
useSWRcon la misma clave dentro de esa ventana, solo se realiza una solicitud de red. - No es lo mismo que el almacenamiento en caché: solo evita solicitudes duplicadas concurrentes.
¿Cómo fusionan sus valores los proveedores SWRConfig anidados?
Los valores del SWRConfig interno se fusionan con los externos y los sobrescriben. Por ejemplo, un proveedor interno puede definir refreshInterval mientras hereda el fetcher del proveedor externo.
¿Qué ocurre si el fetcher no lanza errores en respuestas HTTP no 2xx?
SWR tratará la respuesta como datos exitosos. El valor error siempre será undefined, incluso en respuestas 404 o 500. Comprueba siempre res.ok en tu fetcher y lanza un error si es false.
¿Cómo puedo acceder a los valores del SWRConfig padre al definir una configuración anidada?
Pasa una función en lugar de un objeto a la prop value:
<SWRConfig
value={(parentConfig) => ({
...parentConfig,
refreshInterval: 5000,
})}
>
{children}
</SWRConfig>¿Es seguro definir refreshInterval globalmente en SWRConfig?
Funciona, pero aplica polling a cada hook useSWR del árbol. Prefiere definir refreshInterval por hook a menos que realmente necesites que todas las consultas hagan polling a la misma frecuencia.
¿Cómo tipar el objeto value de SWRConfig en TypeScript?
Importa SWRConfiguration desde swr y úsalo como tipo:
import type { SWRConfiguration } from "swr";
const config: SWRConfiguration = {
fetcher: (url: string) => fetch(url).then((r) => r.json()),
revalidateOnFocus: false,
};¿Qué tipo de TypeScript acepta la prop value de SWRConfig?
Acepta Partial<SWRConfiguration> o una función (parentConfig: SWRConfiguration) => SWRConfiguration que recibe la configuración del padre y devuelve una nueva.
¿Puedo añadir cabeceras de autorización al fetcher global?
Sí. Define un fetcher personalizado que incluya cabeceras:
const authedFetcher = (url: string) =>
fetch(url, {
headers: { Authorization: `Bearer ${getToken()}` },
}).then((res) => {
if (!res.ok) throw new Error("Error al obtener los datos");
return res.json();
});Trampa: ¿Cuál es un error común al omitir el fetcher en llamadas individuales a useSWR?
Si no hay un proveedor SWRConfig envolviendo el componente (o el proveedor no define un fetcher), useSWR no tendrá fetcher y nunca obtendrá datos en silencio. Asegúrate siempre de que exista un proveedor con fetcher por encima de tus componentes.
¿Dónde debe colocarse SWRProvider en un proyecto con Next.js App Router?
Envuélvelo alrededor de {children} en tu app/layout.tsx raíz para que cada página y componente herede la configuración compartida.