Enrutamiento del lado del cliente en Next.js

Publicado: 2022-03-10
Resumen rápido ↬ Next.js tiene un sistema de enrutamiento basado en archivos en el que cada página se convierte automáticamente en una ruta según su nombre de archivo. Cada página es un componente React exportado predeterminado del directorio de páginas que se puede usar para definir los patrones de ruta más comunes. Este artículo lo guiará a través de casi todo lo que necesita saber sobre el enrutamiento en Next.js y lo guiará en la dirección de temas y conceptos relacionados.

Los hipervínculos han sido una de las joyas de la Web desde sus inicios. Según MDN, los hipervínculos son lo que hace que la Web sea una web. Si bien se utiliza para fines como la vinculación entre documentos, su uso principal es hacer referencia a diferentes páginas web identificables por una dirección web única o una URL.

El enrutamiento es un aspecto importante de cada aplicación web tanto como lo son los hipervínculos a la Web. Es un mecanismo a través del cual las solicitudes se enrutan al código que las maneja. En relación con el enrutamiento, las páginas de Next.js son referenciadas e identificables por una ruta de URL única. Si la web consiste en páginas web de navegación interconectadas por hipervínculos , entonces cada aplicación Next.js consta de páginas que se pueden enrutar (controladores de ruta o rutas) interconectadas por un enrutador.

Next.js tiene soporte incorporado para el enrutamiento que puede ser difícil de desempaquetar, especialmente cuando se considera la representación y la obtención de datos. Como requisito previo para comprender el enrutamiento del lado del cliente en Next.js, es necesario tener una visión general de conceptos como el enrutamiento, la representación y la obtención de datos en Next.js.

Este artículo será beneficioso para los desarrolladores de React que estén familiarizados con Next.js y deseen aprender cómo maneja el enrutamiento. Debe tener un conocimiento práctico de React y Next.js para aprovechar al máximo el artículo, que trata únicamente sobre el enrutamiento del lado del cliente y los conceptos relacionados en Next.js.

Enrutamiento y renderizado

El enrutamiento y el renderizado son complementarios entre sí y jugarán un papel importante a lo largo de este artículo. Me gusta cómo los explica Gaurav:

El enrutamiento es el proceso a través del cual el usuario navega a diferentes páginas en un sitio web.

La representación es el proceso de poner esas páginas en la interfaz de usuario. Cada vez que solicita una ruta a una página en particular, también está procesando esa página, pero no todos los renderizados son el resultado de una ruta.

Tómate cinco minutos para pensar en eso.

Lo que debe comprender acerca de la representación en Next.js es que cada página se procesa previamente junto con el código JavaScript mínimo necesario para que se vuelva completamente interactiva a través de un proceso conocido como hidratación. La forma en que Next.js hace esto depende en gran medida de la forma de renderizado previo: generación estática o renderizado del lado del servidor , que están altamente acoplados a la técnica de obtención de datos utilizada y separados por cuándo se genera el HTML para una página.

Según sus requisitos de obtención de datos, es posible que utilice funciones de obtención de datos integradas como getStaticProps , getStaticPaths o getServerSideProps , herramientas de obtención de datos del lado del cliente como SWR, react-query o enfoques tradicionales de obtención de datos como fetch-on- renderizar, buscar y luego renderizar, renderizar mientras se busca (con suspenso).

La representación previa (antes de la representación, a la interfaz de usuario ) es complementaria al enrutamiento y está muy relacionada con la obtención de datos, un tema completo propio en Next.js. Entonces, si bien estos conceptos son complementarios o están estrechamente relacionados, este artículo se centrará únicamente en la mera navegación entre páginas (enrutamiento), con referencias a conceptos relacionados cuando sea necesario.

Con eso fuera del camino, comencemos con la esencia fundamental: Next.js tiene un enrutador basado en un sistema de archivos construido sobre el concepto de páginas.

¡Más después del salto! Continúe leyendo a continuación ↓

Paginas

Las páginas en Next.js son componentes de React que están disponibles automáticamente como rutas. Se exportan como exportaciones predeterminadas desde el directorio de páginas con extensiones de archivo admitidas como .js , .jsx , .ts o .tsx .

Una aplicación típica de Next.js tendrá una estructura de carpetas con directorios de nivel superior como páginas , público y estilos.

 next-app ├── node_modules ├── pages │ ├── index.js // path: base-url (/) │ ├── books.jsx // path: /books │ └── book.ts // path: /book ├── public ├── styles ├── .gitignore ├── package.json └── README.md

Cada página es un componente de React:

 // pages/books.js — `base-url/book` export default function Book() { return

Libros

}

Nota : tenga en cuenta que las páginas también pueden denominarse "controladores de ruta".

Páginas personalizadas

Estas son páginas especiales que residen en el directorio de páginas pero que no participan en el enrutamiento. Tienen el prefijo del símbolo de guión bajo, como en _app.js y _document.js .

  • _app.js
    Este es un componente personalizado que reside en la carpeta de páginas. Next.js usa este componente para inicializar páginas.
  • _document.js
    Al igual que _app.js , _document.js es un componente personalizado que utiliza Next.js para aumentar las etiquetas <html> y <body> de sus aplicaciones. Esto es necesario porque las páginas de Next.js omiten la definición del marcado del documento circundante.
 next-app ├── node_modules ├── pages │ ├── _app.js // ️ Custom page (unavailable as a route) │ ├── _document.jsx // ️ Custom page (unavailable as a route) │ └── index.ts // path: base-url (/) ├── public ├── styles ├── .gitignore ├── package.json └── README.md

Vinculación entre páginas

Next.js expone un componente de Link de la API next/link que se puede usar para realizar transiciones de ruta del lado del cliente entre páginas.

 // Import the <Link/> component import Link from "next/link"; // This could be a page component export default function TopNav() { return ( <nav> <Link href="/">Home</Link> <Link href="/">Publications</Link> <Link href="/">About</Link> </nav> ) } // This could be a non-page component export default function Publications() { return ( <section> <TopNav/> {/* ... */} </section> ) }

El componente Link se puede utilizar dentro de cualquier componente, página o no. Cuando se usa en su forma más básica, como en el ejemplo anterior, el componente Link se traduce en un hipervínculo con un atributo href . (Más información sobre el Link en la siguiente sección/enlace a continuación).

Enrutamiento

El sistema de enrutamiento basado en archivos Next.js se puede usar para definir los patrones de ruta más comunes. Para adaptarse a estos patrones, cada ruta se separa en función de su definición.

Índice Rutas

De forma predeterminada, en su aplicación Next.js, la ruta inicial/predeterminada es pages/index.js , que sirve automáticamente como punto de partida de su aplicación como / . Con una URL base de localhost:3000 , se puede acceder a esta ruta de índice en el nivel de URL base de la aplicación en el navegador.

Las rutas de índice actúan automáticamente como la ruta predeterminada para cada directorio y pueden eliminar las redundancias de nombres. La siguiente estructura de directorios expone dos rutas de ruta: / y /home .

 next-app └── pages ├── index.js // path: base-url (/) └── home.js // path: /home

La eliminación es más evidente con las rutas anidadas .

Rutas anidadas

Una ruta como pages/book tiene un nivel de profundidad. Profundizar es crear rutas anidadas, lo que requiere una estructura de carpetas anidadas. Con una URL base de https://www.smashingmagazine.com , puede acceder a la ruta https://www.smashingmagazine.com/printed-books/printed-books creando una estructura de carpetas similar a la siguiente:

 next-app └── pages ├── index.js // top index route └── printed-books // nested route └── printed-books.js // path: /printed-books/printed-books

O elimine la redundancia de ruta con rutas de índice y acceda a la ruta para libros impresos en https://www.smashingmagazine.com/printed-books .

 next-app └── pages ├── index.js // top index route └── printed-books // nested route └── index.js // path: /printed-books

Las rutas dinámicas también juegan un papel importante en la eliminación de redundancias.

Rutas Dinámicas

Del ejemplo anterior, usamos la ruta de índice para acceder a todos los libros impresos. Para acceder a libros individuales es necesario crear diferentes rutas para cada libro como:

 // ️ Don't do this. next-app └── pages ├── index.js // top index route └── printed-books // nested route ├── index.js // path: /printed-books ├── typesript-in-50-lessons.js // path: /printed-books/typesript-in-50-lessons ├── checklist-cards.js // path: /printed-books/checklist-cards ├── ethical-design-handbook.js // path: /printed-books/ethical-design-handbook ├── inclusive-components.js // path: /printed-books/inclusive-components └── click.js // path: /printed-books/click

que es altamente redundante, no escalable y puede remediarse con rutas dinámicas como:

 // Do this instead. next-app └── pages ├── index.js // top index route └── printed-books ├── index.js // path: /printed-books └── [book-id].js // path: /printed-books/:book-id

La sintaxis de paréntesis — [book-id] — es el segmento dinámico y no se limita solo a los archivos. También se puede usar con carpetas como el ejemplo a continuación, haciendo que el autor esté disponible en la ruta /printed-books/:book-id/author .

 next-app └── pages ├── index.js // top index route └── printed-books ├── index.js // path: /printed-books └── [book-id] └── author.js // path: /printed-books/:book-id/author

El (los) segmento (s) dinámico (s) de una ruta se exponen como un parámetro de consulta al que se puede acceder en cualquiera de los componentes de conexión involucrados en la ruta con el objeto de query del gancho useRouter() — (Más sobre esto en la siguiente sección de la API del enrutador) ).

 // printed-books/:book-id import { useRouter } from 'next/router'; export default function Book() { const { query } = useRouter(); return ( <div> <h1> book-id <em>{query['book-id']}</em> </h1> </div> ); }
 // /printed-books/:book-id/author import { useRouter } from 'next/router'; export default function Author() { const { query } = useRouter(); return ( <div> <h1> Fetch author with book-id <em>{query['book-id']}</em> </h1> </div> ); }

Ampliación de segmentos de rutas dinámicas con Catch All Routes

Ha visto la sintaxis de corchete de segmento de ruta dinámica como en el ejemplo anterior con [book-id].js . La belleza de esta sintaxis es que lleva las cosas aún más lejos con Catch-All Routes . Puede inferir lo que esto hace por el nombre: captura todas las rutas.

Cuando observamos el ejemplo dinámico, aprendimos cómo ayuda a eliminar la redundancia en la creación de archivos para que una sola ruta acceda a varios libros con su ID. Pero hay algo más que podríamos haber hecho.

Específicamente, teníamos la ruta /printed-books/:book-id , con una estructura de directorios:

 next-app └── pages ├── index.js └── printed-books ├── index.js └── [book-id].js

Si actualizamos la ruta para tener más segmentos como categorías, podríamos terminar con algo como: /printed-books/design/:book-id , /printed-books/engineering/:book-id , o mejor aún /printed-books/:category/:book-id .

Agreguemos el año de publicación: /printed-books/:category/:release-year/:book-id . ¿Puedes ver un patrón? La estructura del directorio se convierte en:

 next-app └── pages ├── index.js └── printed-books └── [category] └── [release-year] └── [book-id].js

Sustituimos el uso de archivos con nombre por rutas dinámicas, pero de alguna manera terminamos con otra forma de redundancia. Bueno, hay una solución: Capturar todas las rutas que elimina la necesidad de rutas profundamente anidadas:

 next-app └── pages ├── index.js └── printed-books └── [...slug].js

Utiliza la misma sintaxis de paréntesis excepto que tiene el prefijo de tres puntos. Piense en los puntos como la sintaxis extendida de JavaScript. Quizás se pregunte: si uso las rutas generales, ¿cómo accedo a la categoría ( [category] ) y al año de publicación ( [release-year] ). Dos caminos:

  1. En el caso del ejemplo de los libros impresos, el objetivo final es el libro, y la información de cada libro tendrá sus metadatos adjuntos, o
  2. Los segmentos "slug" se devuelven como una matriz de parámetros de consulta.
 import { useRouter } from 'next/router'; export default function Book() { const { query } = useRouter(); // There's a brief moment where `slug` is undefined // so we use the Optional Chaining (?.) and Nullish coalescing operator (??) // to check if slug is undefined, then fall back to an empty array const [category, releaseYear, bookId] = query?.slug ?? []; return ( <table> <tbody> <tr> <th>Book Id</th> <td>{bookId}</td> </tr> <tr> <th>Category</th> <td>{category}</td> </tr> <tr> <th>Release Year</th> <td>{releaseYear}</td> </tr> </tbody> </table> ); }

Aquí hay más ejemplos para la ruta /printed-books/[…slug] :

Sendero Parámetro de consulta
/printed-books/click.js { “slug”: [“clic”] }
/printed-books/2020/click.js { "babosa": ["2020", "clic"] }
/printed-books/design/2020/click.js { “slug”: [“diseño”, “2020”, “clic”] }

Como ocurre con la ruta catch-all, la ruta /printed-books generará un error 404 a menos que proporcione una ruta de índice de reserva.

 next-app └── pages ├── index.js └── printed-books ├── index.js // path: /printed-books └── [...slug].js

Esto se debe a que la ruta general es "estricta". O coincide con un slug o arroja un error. Si desea evitar crear rutas de índice junto con rutas generales, puede usar las rutas generales opcionales en su lugar.

Ampliación de segmentos de rutas dinámicas con rutas Catch-All opcionales

La sintaxis es la misma que la de catch-all-routes, pero con corchetes dobles en su lugar.

 next-app └── pages ├── index.js └── printed-books └── [[...slug]].js

En este caso, la ruta catch-all (slug) es opcional y, si no está disponible, recurre a la ruta /printed-books , representada con el controlador de ruta [[…slug]].js , sin ningún parámetro de consulta.

Utilice rutas catch-all junto con rutas de índice o solo rutas catch-all opcionales. Evite el uso de rutas catch-all y catch-all opcionales al lado.

Prioridad de rutas

La capacidad de poder definir los patrones de enrutamiento más comunes puede ser un "cisne negro". La posibilidad de que las rutas entren en conflicto es una amenaza inminente, especialmente cuando comienza a trabajar con rutas dinámicas.

Cuando tiene sentido hacerlo, Next.js le informa sobre los conflictos de rutas en forma de errores. Cuando no es así, aplica prioridad a las rutas según su especificidad.

Por ejemplo, es un error tener más de una ruta dinámica en el mismo nivel.

 // This is an error // Failed to reload dynamic routes: Error: You cannot use different slug names for the // same dynamic path ('book-id' !== 'id'). next-app └── pages ├── index.js └── printed-books ├── [book-id].js └── [id].js

Si observa detenidamente las rutas definidas a continuación, notará la posibilidad de conflictos.

 // Directory structure flattened for simplicity next-app └── pages ├── index.js // index route (also a predefined route) └── printed-books ├── index.js ├── tags.js // predefined route ├── [book-id].js // handles dynamic route └── [...slug].js // handles catch all route

Por ejemplo, intente responder esto: ¿qué ruta maneja la ruta /printed-books/inclusive-components ?

  • /printed-books/[book-id].js , o
  • /printed-books/[…slug].js .

La respuesta radica en la "especificidad" de los controladores de ruta. Las rutas predefinidas son lo primero, seguidas de las rutas dinámicas y luego las rutas generales. Puede pensar en el modelo de manejo/solicitud de ruta como un pseudocódigo con los siguientes pasos:

  1. ¿Hay un controlador de ruta predefinido que pueda manejar la ruta?
    • true : maneja la solicitud de ruta.
    • false : vaya a 2.
  2. ¿Hay un controlador de ruta dinámico que pueda manejar la ruta?
    • true : maneja la solicitud de ruta.
    • false : vaya a 3.
  3. ¿Hay un controlador de ruta general que pueda manejar la ruta?
    • true : maneja la solicitud de ruta.
    • false : lanza una página 404 no encontrada.

Por lo tanto, /printed-books/[book-id].js gana.

Aquí hay más ejemplos:

Ruta Controlador de ruta tipo de ruta
/printed-books /printed-books Índice de ruta
/printed-books/tags /printed-books/tags.js Ruta predefinida
/printed-books/inclusive-components /printed-books/[book-id].js Ruta Dinámica
/printed-books/design/inclusive-components /printed-books/[...slug].js Ruta general

La API next/link

La API next/link expone el componente Link como una forma declarativa de realizar transiciones de ruta del lado del cliente.

 import Link from 'next/link' function TopNav() { return ( <nav> <Link href="/">Smashing Magazine</Link> <Link href="/articles">Articles</Link> <Link href="/guides">Guides</Link> <Link href="/printed-books">Books</Link> </nav> ) }

El componente Link se resolverá en un hipervínculo HTML normal. Es decir, <Link href="/">Smashing Magazine</Link> se resolverá como <a href="/">Smashing Magazine</a> .

La propiedad href es la única propiedad necesaria para el componente Link . Consulte los documentos para obtener una lista completa de accesorios disponibles en el componente Link .

Hay otros mecanismos del componente Link a tener en cuenta.

Rutas con segmentos dinámicos

Antes de Link 9.5.3, la vinculación a rutas dinámicas significaba que tenía que proporcionar tanto el href as accesorio a Link como en:

 import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href="/printed-books/[printed-book-id]" as={`/printed-books/${printedBook.id}`} > {printedBook.name} </Link> )); }

Aunque esto permitió que Next.js interpolara el href para los parámetros dinámicos, era tedioso, propenso a errores y algo imperativo, y ahora se solucionó para la mayoría de los casos de uso con el lanzamiento de Next.js 10.

Esta solución también es compatible con versiones anteriores. Si ha estado usando as y href , nada se rompe. Para adoptar la nueva sintaxis, descarte href prop y su valor, y cambie el nombre de as prop a href como en el siguiente ejemplo:

 import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href={`/printed-books/${printedBook.id}`}>{printedBook.name}</Link> )); }

Consulte Resolución automática de href.

Casos de uso para la passHref

Eche un vistazo de cerca al fragmento a continuación:

 import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; // Say this has some sort of base styling attached function CustomLink({ href, name }) { return <a href={href}>{name}</a>; } export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href={`/printed-books/${printedBook.id}`} passHref> <CustomLink name={printedBook.name} /> </Link> )); }

Los accesorios passHref obligan al componente Link a pasar el accesorio href al componente secundario CustomLink . Esto es obligatorio si el componente Link envuelve un componente que devuelve una etiqueta de hipervínculo <a> . Su caso de uso podría deberse a que está utilizando una biblioteca como componentes con estilo, o si necesita pasar varios elementos secundarios al componente Link , ya que solo espera un solo elemento secundario.

Consulte los documentos para obtener más información.

Objetos de URL

El href prop del componente Link también puede ser un objeto de URL con propiedades como query que se formatea automáticamente en una cadena de URL.

Con el objeto printedBooks , el siguiente ejemplo se vinculará a:

  1. /printed-books/ethical-design?name=Ethical+Design y
  2. /printed-books/design-systems?name=Design+Systems .
 import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href={{ pathname: `/printed-books/${printedBook.id}`, query: { name: `${printedBook.name}` }, }} > {printedBook.name} </Link> )); }

Si incluye un segmento dinámico en el nombre de la pathname , también debe incluirlo como una propiedad en el objeto de consulta para asegurarse de que la consulta se interpole en el nombre de la pathname :

 import Link from 'next/link'; const printedBooks = [ { name: 'Ethical Design', id: 'ethical-design' }, { name: 'Design Systems', id: 'design-systems' }, ]; // In this case the dynamic segment `[book-id]` in pathname // maps directly to the query param `book-id` export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href={{ pathname: `/printed-books/[book-id]`, query: { 'book-id': `${printedBook.id}` }, }} > {printedBook.name} </Link> )); }

El ejemplo anterior tiene rutas:

  1. /printed-books/ethical-design , y
  2. /printed-books/design-systems .

Si inspecciona el atributo href en VSCode, encontrará el tipo LinkProps , con la propiedad href un tipo Url , que es una string o UrlObject como se mencionó anteriormente.

Una captura de pantalla del tipo LinkProps inspeccionado en VSCode
Inspección de LinkProps en VSCode. (Vista previa grande)

La inspección de UrlObject conduce a la interfaz con las propiedades:

Una captura de pantalla del <code>UrlObject</code> inspeccionado en VSCode
Inspeccionando UrlObject en VSCode. (Vista previa grande)

Puede obtener más información sobre estas propiedades en la documentación del módulo URL de Node.js.

Un caso de uso del hash es vincular a secciones específicas de una página.

 import Link from 'next/link'; const printedBooks = [{ name: 'Ethical Design', id: 'ethical-design' }]; export default function PrintedBooks() { return printedBooks.map((printedBook) => ( <Link href={{ pathname: `/printed-books/${printedBook.id}`, hash: 'faq', }} > {printedBook.name} </Link> )); }

El hipervínculo se resolverá en /printed-books/ethical-design#faq .

Obtenga más información en los documentos.

La next/router

Si next/link es declarativo, entonces next/router es imperativo. Expone un gancho useRouter que permite el acceso al objeto del router dentro de cualquier componente de función. Puede usar este gancho para realizar el enrutamiento manualmente, especialmente en ciertos escenarios donde el next/link no es suficiente, o donde necesita "enganchar" al enrutamiento.

 import { useRouter } from 'next/router'; export default function Home() { const router = useRouter(); function handleClick(e) { e.preventDefault(); router.push(href); } return ( <button type="button" onClick={handleClick}>Click me</button> ) }

useRouter es un enlace de React y no se puede usar con clases. ¿Necesita el objeto de router en los componentes de clase? Usar withRouter .

 import { withRouter } from 'next/router'; function Home({router}) { function handleClick(e) { e.preventDefault(); router.push(href); } return ( <button type="button" onClick={handleClick}>Click me</button> ) } export default withRouter(Home);

El objeto router

Tanto el useRouter como el componente de orden superior withRouter devuelven un objeto de enrutador con propiedades como pathname , query , asPath y basePath que le brindan información sobre el estado de URL de la página actual, locale , locales y defaultLocale que brinda información sobre el configuración regional predeterminada activa, admitida o actual.

El objeto de enrutador también tiene métodos como push para navegar a una nueva URL agregando una nueva entrada de URL en la pila de historial, replace , similar a empujar pero reemplaza la URL actual en lugar de agregar una nueva entrada de URL en la pila de historial.

Obtenga más información sobre el objeto de enrutador.

Configuración de ruta personalizada con next.config.js

Este es un módulo normal de Node.js que se puede usar para configurar cierto comportamiento de Next.js.

 module.exports = { // configuration options }

Recuerde reiniciar su servidor cada vez que actualice next.config.js . Aprende más.

Ruta básica

Se mencionó que la ruta inicial/predeterminada en Next.js es pages/index.js con la ruta / . Esto es configurable y puede hacer que su ruta predeterminada sea una ruta secundaria del dominio.

 module.exports = { // old default path: / // new default path: /dashboard basePath: '/dashboard', };

Estos cambios surtirán efecto automáticamente en su aplicación con todas las rutas enrutadas a / /dashboard .

Esta característica solo se puede usar con Next.js 9.5 y superior. Aprende más.

Barra diagonal

De forma predeterminada, una barra diagonal final no estará disponible al final de cada URL. Sin embargo, puedes cambiar eso con:

 module.exports = { trailingSlash: true };
 # trailingSlash: false /printed-books/ethical-design#faq # trailingSlash: true /printed-books/ethical-design/#faq

Tanto la ruta base como las funciones de barra inclinada final solo se pueden usar con Next.js 9.5 y versiones posteriores.

Conclusión

El enrutamiento es una de las partes más importantes de su aplicación Next.js y se refleja en el enrutador basado en el sistema de archivos construido sobre el concepto de páginas. Las páginas se pueden utilizar para definir los patrones de ruta más comunes. Los conceptos de enrutamiento y renderizado están estrechamente relacionados. Tome las lecciones de este artículo con usted mientras crea su propia aplicación Next.js o trabaja en una base de código de Next.js. Y consulte los recursos a continuación para obtener más información.

Recursos Relacionados

  • Documentación oficial de Next.js para Pages
  • Documentación oficial de Next.js para la obtención de datos
  • Documentación oficial de Next.js para next.config.js
  • Next.js 10: resolución automática de href
  • Documentación oficial de Next.js para next/link
  • Documentación oficial de Next.js para next/router