Cómo construir aplicaciones de una sola página con Next.js
Next.js ofrece soporte completo para construir Aplicaciones de Una Sola Página (SPAs, por sus siglas en inglés).
Esto incluye transiciones rápidas entre rutas con precarga (prefetching), obtención de datos del lado del cliente (client-side data fetching), uso de APIs del navegador, integración con bibliotecas de terceros para el cliente, creación de rutas estáticas y más.
Si ya tienes una SPA existente, puedes migrarla a Next.js sin realizar grandes cambios en tu código. Next.js te permite añadir progresivamente características del servidor según las necesites.
¿Qué es una Aplicación de Una Sola Página?
La definición de una SPA puede variar. Definiremos una "SPA estricta" como:
- Renderizado del lado del cliente (CSR): La aplicación se sirve mediante un único archivo HTML (ej.
index.html
). Cada ruta, transición de página y obtención de datos se maneja mediante JavaScript en el navegador. - Sin recargas completas de página: En lugar de solicitar un nuevo documento para cada ruta, el JavaScript del cliente manipula el DOM de la página actual y obtiene los datos según sea necesario.
Las SPAs estrictas suelen requerir grandes cantidades de JavaScript para cargar antes de que la página pueda ser interactiva. Además, las cascadas de datos en el cliente pueden ser difíciles de gestionar. Construir SPAs con Next.js puede abordar estos problemas.
¿Por qué usar Next.js para SPAs?
Next.js puede dividir automáticamente tus paquetes de JavaScript (code splitting) y generar múltiples puntos de entrada HTML para diferentes rutas. Esto evita cargar código JavaScript innecesario en el cliente, reduciendo el tamaño del paquete y permitiendo cargas de página más rápidas.
El componente next/link
precarga automáticamente las rutas, ofreciéndote las rápidas transiciones de página de una SPA estricta, pero con la ventaja de persistir el estado de enrutamiento de la aplicación en la URL para compartir y enlazar.
Next.js puede comenzar como un sitio estático o incluso como una SPA estricta donde todo se renderiza del lado del cliente. Si tu proyecto crece, Next.js te permite añadir progresivamente más características del servidor (ej. Componentes de Servidor de React, Acciones de Servidor, etc.) según sea necesario.
Ejemplos
Exploremos patrones comunes utilizados para construir SPAs y cómo Next.js los resuelve.
Usar el hook use
de React dentro de un Context Provider
Recomendamos obtener datos en un componente padre (o layout), devolver la Promise y luego desempaquetar el valor en un Componente Cliente con el hook use
de React.
Next.js puede comenzar a obtener datos tempranamente en el servidor. En este ejemplo, ese es el layout raíz — el punto de entrada de tu aplicación. El servidor puede comenzar inmediatamente a transmitir una respuesta al cliente.
Al "elevar" (hoisting) tu obtención de datos al layout raíz, Next.js inicia las solicitudes especificadas en el servidor antes que cualquier otro componente en tu aplicación. Esto elimina cascadas en el cliente y evita múltiples viajes de ida y vuelta entre cliente y servidor. También puede mejorar significativamente el rendimiento, ya que tu servidor está más cerca (y idealmente ubicado junto) a donde se encuentra tu base de datos.
Por ejemplo, actualiza tu layout raíz para llamar a la Promise, pero no la esperes (await).
Si bien puedes diferir y pasar una sola Promise como prop a un Componente Cliente, generalmente vemos este patrón emparejado con un proveedor de contexto de React. Esto facilita el acceso desde Componentes Cliente con un Hook personalizado de React.
Puedes pasar una Promise al proveedor de contexto de React:
Finalmente, puedes llamar al hook personalizado useUser()
en cualquier Componente Cliente y desempaquetar la Promise:
El componente que consume la Promise (ej. Profile
arriba) será suspendido. Esto permite hidratación parcial. Puedes ver el HTML transmitido (streamed) y prerenderizado antes de que JavaScript haya terminado de cargar.
SPAs con SWR
SWR es una biblioteca popular de React para obtención de datos.
Con SWR 2.3.0 (y React 19+), puedes adoptar gradualmente características del servidor junto con tu código existente de obtención de datos del cliente basado en SWR. Esta es una abstracción del patrón use()
mencionado anteriormente. Esto significa que puedes mover la obtención de datos entre el cliente y el servidor, o usar ambos:
- Solo cliente:
useSWR(key, fetcher)
- Solo servidor:
useSWR(key)
+ datos proporcionados por RSC - Mixto:
useSWR(key, fetcher)
+ datos proporcionados por RSC
Por ejemplo, envuelve tu aplicación con <SWRConfig>
y un fallback
:
Como este es un Componente Servidor, getUser()
puede leer cookies, encabezados o comunicarse con tu base de datos de forma segura. No se necesita una ruta API separada. Los componentes cliente debajo de <SWRConfig>
pueden llamar a useSWR()
con la misma clave para recuperar los datos del usuario. El código del componente con useSWR
no requiere ningún cambio respecto a tu solución existente de obtención en el cliente.
Los datos de fallback
pueden prerenderizarse e incluirse en la respuesta HTML inicial, luego leerse inmediatamente en los componentes hijos usando useSWR
. La sondeo (polling), revalidación y caché de SWR siguen ejecutándose solo del lado del cliente, por lo que preserva toda la interactividad que necesitas para una SPA.
Como los datos iniciales de fallback
son manejados automáticamente por Next.js, ahora puedes eliminar cualquier lógica condicional previamente necesaria para verificar si data
era undefined
. Cuando los datos se están cargando, se suspenderá el límite <Suspense>
más cercano.
SWR | RSC | RSC + SWR | |
---|---|---|---|
Datos SSR | |||
Streaming durante SSR | |||
Desduplicar solicitudes | |||
Características del cliente |
SPAs con React Query
Puedes usar React Query con Next.js tanto en el cliente como en el servidor. Esto te permite construir tanto SPAs estrictas como aprovechar características del servidor en Next.js junto con React Query.
Aprende más en la documentación de React Query.
Renderizar componentes solo en el navegador
Los componentes cliente son prerenderizados durante next build
. Si deseas desactivar el prerenderizado para un Componente Cliente y cargarlo solo en el entorno del navegador, puedes usar next/dynamic
:
Esto puede ser útil para bibliotecas de terceros que dependen de APIs del navegador como window
o document
. También puedes añadir un useEffect
que verifique la existencia de estas APIs, y si no existen, devolver null
o un estado de carga que sería prerenderizado.
Enrutamiento superficial en el cliente
Si estás migrando desde una SPA estricta como Create React App o Vite, podrías tener código existente que realiza enrutamiento superficial para actualizar el estado de la URL. Esto puede ser útil para transiciones manuales entre vistas en tu aplicación sin usar el enrutamiento basado en archivos predeterminado de Next.js.
Next.js te permite usar los métodos nativos window.history.pushState
y window.history.replaceState
para actualizar el historial del navegador sin recargar la página.
Las llamadas pushState
y replaceState
se integran con el Enrutador de Next.js, permitiéndote sincronizar con usePathname
y useSearchParams
.
Aprende más sobre cómo funcionan el enrutamiento y navegación en Next.js.
Usar Acciones de Servidor en Componentes Cliente
Puedes adoptar progresivamente Acciones de Servidor mientras sigues usando Componentes Cliente. Esto te permite eliminar código repetitivo para llamar a una ruta API, y en su lugar usar características de React como useActionState
para manejar estados de carga y error.
Por ejemplo, crea tu primera Acción de Servidor:
Puedes importar y usar una Acción de Servidor desde el cliente, similar a llamar a una función JavaScript. No necesitas crear manualmente un endpoint API:
Aprende más sobre mutación de datos con Acciones de Servidor.
Exportación estática (opcional)
Next.js también soporta generar un sitio completamente estático. Esto tiene algunas ventajas sobre las SPAs estrictas:
- División de código automática: En lugar de enviar un único
index.html
, Next.js generará un archivo HTML por ruta, por lo que tus visitantes obtendrán el contenido más rápido sin esperar el paquete de JavaScript del cliente. - Mejor experiencia de usuario: En lugar de un esqueleto mínimo para todas las rutas, obtienes páginas completamente renderizadas para cada ruta. Cuando los usuarios navegan del lado del cliente, las transiciones siguen siendo instantáneas y similares a una SPA.
Para habilitar una exportación estática, actualiza tu configuración:
Después de ejecutar next build
, Next.js creará una carpeta out
con los recursos HTML/CSS/JS para tu aplicación.
Nota: Las características de servidor de Next.js no son compatibles con exportaciones estáticas. Aprende más.
Migrar proyectos existentes a Next.js
Puedes migrar incrementalmente a Next.js siguiendo nuestras guías:
Si ya estás usando una SPA con el Pages Router, puedes aprender cómo adoptar incrementalmente el App Router.
Autoalojamiento
Aprende a autoalojar tu aplicación Next.js en un servidor Node.js, imagen Docker o archivos HTML estáticos (exportaciones estáticas).
Exportaciones estáticas
Next.js permite comenzar como un sitio estático o una Aplicación de Página Única (SPA), y luego actualizar opcionalmente para usar funciones que requieran un servidor.