Sebastian Gomez
Enrutando páginas con Next.js
No necesitas interactuar directamente con el router de Next.js para crear y ver páginas en tu sitio. Next.js se construyó con convenciones para hacer el proceso de creación de rutas tan fácil como crear un archivo.
Nota, Pages Router frente a App Router: Este post enseña el Pages Router (la carpeta /pages). Sigue siendo totalmente funcional y soportado, pero desde Next.js 13 el App Router (la carpeta /app) es el paradigma por defecto y recomendado, y es lo que obtienes al correr create-next-app en Next.js 16. Los conceptos que veremos, segmentos dinámicos, captura de todas las rutas y rutas opcionales, existen en ambos; solo cambia la convención de archivos. A lo largo del post te muestro el equivalente en el App Router en cada caso.
Para comenzar solo debes crear una carpeta llamada /pages. Next.js asociará cualquier archivo dentro de este directorio como una ruta. El nombre del archivo determinará también el nombre de la ruta o el patrón de la ruta, y cualquiera que sea el componente exportado dentro de estos archivos será la página que se mostrará.
Por ahora creemos una ruta "index" simplemente creando el archivo dentro de nuestra carpeta pages: /pages/index.js. Luego, creemos un componente y exportémoslo:
export default function IndexPage() {
return <h1>Index Page</h1>
}Inicializa tu servidor de desarrollo:
# npm
$ npm run dev
# yarn
$ yarn devDeberíamos ser capaces de navegar en nuestro navegador a la ruta "index" y ver nuestro h1. Como ves, es súper fácil crear una ruta y tenerla disponible en nuestro proyecto casi que de inmediato. Este tipo de convenciones hace que desarrollar sea más rápido y que puedas enfocarte más en el contenido que en la lógica.
Verás que nada más al abrir el navegador aparece el contenido.
Nota: El archivo index siempre es un caso particular, y más en Next.js, ya que se mostrará por defecto tal cual un archivo HTML. Sin embargo, a diferencia de un sitio web tradicional o de una SPA, la ruta http://localhost:3000/index no existe y se mostrará el error 404 por defecto de Next.js.
Tip: Recuerda que Next.js toma como base la carpeta pages, por tanto la ruta http://localhost:3000/pages/index tampoco existirá a menos que crees una carpeta pages dentro de la carpeta principal pages.
Bien, hemos creado una página "index", pero ¿qué pasa con rutas más complejas como myapp.com/project/settings o myapp.com/user/1, donde el 1 es un parámetro? No te preocupes, Next.js tiene eso cubierto.
Carpetas y rutas
Para crear una ruta como /project/settings podemos usar carpetas dentro de nuestra carpeta principal /pages. Para nuestra aplicación de tomar notas, necesitamos las siguientes rutas por ahora:
index => /
todas las notas => /notes
una nota => /notes/:idYa hemos creado la ruta "index"; creemos la ruta para todas las notas. Para ello creemos una carpeta llamada notes y dentro creemos un archivo index.jsx.
pages
index.jsx
notes
index.jsxAl añadir un archivo "index" dentro de una carpeta, le estamos diciendo a Next.js que queremos que el componente dentro del index sea lo que se muestre cuando se acceda a esta ruta con el nombre de la carpeta. Entonces, en este caso, navegando a /notes se va a renderizar el componente que esté en pages/notes/index.jsx. Coloquemos por ahora dentro del archivo pages/notes/index.jsx lo siguiente:
export default function AllNotesPage() {
return <h1>All notes Page</h1>
}Si navegas a la ruta deberías ver el resultado esperado.
Tip: No siempre es necesario crear la carpeta y el archivo index; también puedes crear solo el archivo y Next.js creará la ruta. Por ejemplo, pages/notes/index.jsx puede ser fácilmente sustituible por pages/notes.jsx y funcionará exactamente igual. Sin embargo, debes tener cuidado con los conflictos entre las rutas. Es completamente incorrecto tener pages/notes/index.jsx y pages/notes.jsx a la vez, ya que Next.js no sabrá cuál de los dos componentes renderizar para dicha ruta.
Rutas dinámicas
Next.js hace fácil la creación de rutas dinámicas. Dependiendo de si quieres que estas páginas sean prerrenderizadas o no, la estrategia dentro del componente cambia; pero por ahora enfoquémonos en páginas que serán construidas cuando el servidor esté corriendo, es decir, en tiempo de ejecución de nuestro servidor y no en tiempo de compilación o "build time".
Para crear una ruta dinámica, podemos crear un archivo que tenga el nombre del parámetro dinámico entre corchetes cuadrados, algo así: [id].jsx. Donde id es el nombre del parámetro. Tú puedes nombrarlo como quieras. Recuerda que los corchetes cuadrados no son un error ni un ejemplo: son la sintaxis estricta de Next.js para crear una ruta dinámica. Por tanto, para crear nuestra ruta de /notes/1 vamos a crear el archivo [id].jsx dentro de nuestra carpeta /notes.
pages
index.jsx
notes
index.jsx
[id].jsxPodemos acceder al parámetro id dentro de nuestra página usando un hook llamado useRouter del módulo next/router. Este ya viene disponible y listo con Next.js.
// Importa el hook 'useRouter' de 'next/router' para acceder al objeto del enrutador
import { useRouter } from 'next/router'
// Componente con nombre exportado por defecto
export default function NotePage() {
// Obtiene una instancia del enrutador de Next.js
const router = useRouter()
// Extrae la propiedad 'id' del objeto 'query' para acceder al valor de 'id' en la ruta actual
const { id } = router.query
// Muestra el valor de 'id' obtenido de la ruta
return <h1>Note: {id}</h1>
}Donde el nombre del parámetro en el objeto router.query es el mismo que el parámetro que está dentro de corchetes cuadrados en el nombre de la página:
router.query.id
|
|
[id].jsxAsí verías el parámetro en tu aplicación.
Equivalente en el App Router: Si tu proyecto usa la carpeta /app, este mismo caso se resuelve creando app/notes/[id]/page.jsx y leyendo el parámetro con useParams de next/navigation (en un Client Component) o desde las props de la página (en un Server Component):
>
```jsx 'use client' import { useParams } from 'next/navigation'
>
export default function NotePage() { const { id } = useParams() return <h1>Note: {id}</h1> } ```
>
Nota: en Next.js 16, en un Server Component las props.params se obtienen de forma asíncrona (const { id } = await params). En Client Components usa el hook useParams().
Capturando todas las rutas
Next.js tiene una funcionalidad bastante bonita que nos ayuda a definir y capturar todas las rutas cuando realmente no queremos hacer una página para cada ruta posible.
¿Cómo sería una ruta capturable? Básicamente son todas las combinaciones posibles de rutas dentro de una, por ejemplo:
this/folder/**Donde el ** significa todo lo que esté dentro del "folder". Nosotros podemos hacer lo mismo con el concepto de rutas dinámicas en Next.js. Lo único que necesitamos hacer es crear un archivo en nuestro directorio con una sintaxis así: docs/[...params].jsx.
Entonces, los tres puntos ... los usa Next.js para entender que toda la estructura de la URL será pasada como parámetro. La diferencia dentro del useRouter será que los parámetros serán un arreglo, exactamente en el mismo orden en que se construyó la ruta:
import { useRouter } from 'next/router'
// El nombre del archivo indica que el componente manejará rutas de la forma /docs/a/b/c
// file => /docs/[...params].jsx
// route => /docs/a/b/c
export default function DocsPage() {
const router = useRouter()
// 'params' será un arreglo con los segmentos de la ruta
const { params } = router.query
// Para la ruta de ejemplo /docs/a/b/c => params === ['a', 'b', 'c']
return <h1>hello {JSON.stringify(params)}</h1>
}No importa el número de segmentos que tenga tu ruta, siempre los pasará como arreglo. Así se vería nuestro componente.
Equivalente en el App Router: El catch all también existe en /app con la misma sintaxis de carpeta: app/docs/[...params]/page.jsx. Allí los segmentos llegan en params (asíncrono en Server Components, o vía useParams en Client Components) y params.params será el arreglo ['a', 'b', 'c'].
Ahora bien, para nuestra página padre, es decir, para la ruta /docs sola, aún se mostraría el error 404, ya que no hemos creado el archivo index.jsx dentro de la carpeta. Sin embargo, si también queremos ahorrarnos la creación de este archivo, podríamos usar otros corchetes cuadrados por fuera de nuestro [...params]:
docs/[[...params]].jsxTip: ¿Cuándo usar esta funcionalidad de capturar todas las rutas? Es realmente útil cuando tienes un conjunto de páginas que tienen similitudes (si es que no son idénticas) en sus layouts y estilos, pero que tienen diferente contenido y necesitan su propia URL. Documentación y wikis son un ejemplo perfecto para usar esta funcionalidad.
Componentes que no son páginas
Las páginas son especiales, pero ¿qué pasa cuando solamente necesitamos componentes de React para usar en nuestras páginas? Next.js no tiene ninguna convención sobre esto. Normalmente estos componentes se crean dentro de la carpeta /src/components, donde colocamos los componentes reutilizables.
Ejercicios propuestos
- Crea un proyecto de Next.js 16 con el Pages Router y reproduce las rutas
/,/notesy/notes/:idtal como las vimos aquí. - Convierte la ruta dinámica
/notes/[id]a su equivalente en el App Router (app/notes/[id]/page.jsx) leyendo el parámetro conuseParams. - Crea una sección de documentación con catch all opcional (
[[...params]]) que muestre tanto/docscomo/docs/a/b/cdesde un mismo archivo.
Resumen en 3 puntos
- En el Pages Router, cada archivo dentro de
/pagesse convierte en una ruta automáticamente;indexes la ruta raíz de su carpeta. - Las rutas dinámicas usan corchetes en el nombre del archivo:
[id].jsxpara un parámetro,[...params].jsxpara capturar todas las rutas y[[...params]].jsxpara hacerlo opcional. - El App Router (
/app) es el paradigma por defecto en Next.js 16; los mismos conceptos aplican cambiandopages/porapp/.../page.jsxyrouter.queryporuseParams.
Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente, o que simplemente te haya ayudado a entender cómo funcionan las rutas en Next.js.
Déjame un comentario si te sirvió, si quieres añadir alguna opinión o si tienes alguna duda. Y recuerda que si te gustó, también puedes compartirlo usando los links a las redes sociales aquí abajo. ¡Buena suerte!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.