Topics

Aclarando las diferencias entre Next.js Pages Router y App Router, que suelen confundirse

  • column

Next.js, un framework de desarrollo web que goza de amplio apoyo, introdujo el nuevo App Router como sistema de enrutamiento predeterminado en la versión 13.

Al trabajar en proyectos que utilizan tanto Pages Router como App Router, es fácil confundirse preguntándose "¿cuál era la sintaxis correcta?". ¡Yo mismo me encuentro en esa situación!

En particular, existen diferencias significativas entre Pages Router y App Router en aspectos fundamentales del desarrollo de aplicaciones: desde la forma de definir el enrutamiento basado en la estructura de archivos, pasando por cómo se manejan las partes dinámicas de las URLs, hasta cómo funcionan el renderizado y la obtención de datos desde APIs.

Me enfocaré en los puntos que tienden a causar confusión y documentaré las principales diferencias entre Pages Router y App Router de manera concisa como referencia personal.

Diferencias en el enrutamiento de archivos

Pages Router: Simplicidad donde el nombre del archivo se convierte directamente en la ruta

La simplicidad radica en que los archivos .js, .jsx, .ts, .tsx colocados dentro del directorio pages se convierten directamente en rutas URL basadas en sus nombres de archivo.

Ejemplo: src/page/about.tsx ⇒ El enrutamiento será /about.

App Router: estructura con carpetas y nombres de archivo específicos

App Router permite enrutar colocando carpetas y archivos dentro de src/app.

Sin embargo, los archivos con el nombre específico "page" se tratan como el contenido de la página correspondiente a esa ruta.

Ejemplo: src/app/about/page.tsx ⇒ El enrutamiento será /about.

Los "archivos especiales" que caracterizan a App Router

Además de page.tsx, App Router también tiene otros archivos con significado especial.

app/
├── page.tsx           --> ページの中身。これが一番よく使うファイル
├── route.tsx          --> APIの定義(page.jsと共存不可)
├── layout.tsx         --> 共通の見た目
├── loading.tsx        --> 読み込み中の画面
├── error.tsx          --> エラー時の画面
├── global-error.tsx   --> グローバルエラー画面
├── templete.tsx       --> 共通の見た目(リセットされるレイアウト)
├── default.tsx        --> デフォルトの画面
└── not-found.tsx      --> notFound関数がスローされたときの画面

Lo que me sorprendió personalmente fue not-found.tsx. Si preparas esta página, se mostrará automáticamente cuando alguien acceda a una URL que no existe. Me quedé asombrado de lo fácil que es implementarlo.

Diferencias en el renderizado

Los componentes en Pages Router están diseñados básicamente para ser interactivos en el lado del cliente, y el renderizado en el lado del servidor se realiza principalmente para acelerar la visualización inicial y mejorar el SEO. Los hooks de React como useState y useEffect se pueden utilizar libremente dentro de componentes de página o sus componentes secundarios.

Por otro lado, los componentes dentro de app/ en App Router son tratados por defecto como componentes de servidor, a menos que se especifique explícitamente lo contrario. Por lo tanto, no se pueden usar hooks de useState ni useEffect de React. Tampoco se pueden usar acciones del lado del cliente como manejadores de eventos (onClick, etc.).

Para usar CSR con App Router, se escribe use client.

use client

Esta es la declaración del límite entre componentes de servidor y componentes de cliente. Cuando se declara use client, no solo ese componente, sino también todos los componentes que importa se consideran componentes de cliente.

Enrutamiento dinámico [○○]

El enrutamiento dinámico de Next.js es un mecanismo para manejar «URLs dinámicas» donde parte de la URL cambia según el usuario o el contenido, como en páginas de detalle de artículos de blogs o noticias.

Por ejemplo, supongamos que hay enlaces que navegan hacia el artículo A y el artículo B.

Por ejemplo, captura de pantalla de una página con enlaces que navegan hacia el artículo A y el artículo B
import Link from "next/link";
const linkStyle=`ext-lg font-bold border-b border-primary px-1`

export default function page() {
  return (
    <div>
      <div className="flex gap-6">
        <Link href="/post/A" className={linkStyle}>記事Aへのリンク</Link>
        <Link href="/post/B" className={linkStyle}>記事Bへのリンク</Link>
      </div>
    </div>
  );
}

Destino de navegación de cada enlace

Captura de pantalla de la página post/A
Captura de pantalla de la página post/B

Para usar enrutamiento dinámico, si se crea un archivo llamado [slug], se puede usar la misma plantilla tanto para post/A como para post/B.
*El nombre dentro de [ ] es arbitrario, así que no tiene que ser slug

En el caso de App Router

/app/post/[slug]/page.tsx

export default aysinc function PostPage({ params }: { params: Promise<{ slug: string }>) {
  const {slug}= await params;
  return (
    <div>
      <h1>記事: {slug}</h1>
    </div>
  );
}

Se usa params. En params.slug se almacena la parte [slug] de la URL.

* params no necesitaba ser asincrónico anteriormente, pero a partir de Next.js 15 se cambió para ser asincrónico. Por lo tanto, parece que es necesario definir props como tipo Promise.

En el caso de Pages Router

/pages/post/[slug].tsx


import { useRouter } from 'next/router';

export default function PostPage() {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div>
      <h1>記事: {slug}</h1>
    </div>
  );
}

Usamos useRouter. El valor de la parte [slug] de la URL se almacena en router.query.slug.

Método de obtención de datos de API

microCMS, que también es muy activo en la columna de Liberogic, es muy compatible con marcos como Next.js.

En el caso de App Router

Simplemente puede usar fetch o async await.

Sin embargo, los archivos que declaran use client se convierten en CSR, por lo que async await ya no se pueden usar.


async function getPost() {
  const res = await fetch(`https://.../api/data/`);

  // エラーハンドリング例
  if (!res.ok) {
     throw new Error(`Failed to fetch post: ${res.status}`);
  }

  return res.json();
}

Destino de la llamada

export default function Example() {
   const data = await getPost()
   // ... data を使って表示 ...
}

En el caso de Pages Router

Usamos getStaticProps y pasamos los datos obtenidos como props al componente de página.


export async function getServerSideProps(context) {
  // context.req, context.res などにアクセス可能
  const res = await fetch(`https://.../api/data/`, {
     headers: { Cookie: context.req.headers.cookie } // 例: Cookieを渡す
  });
  const data = await res.json();

  return {
    props: {
      data,
    },
  };
}

Destino de la llamada

export default function Example({ data }) {
  // ... data を使って表示 ...
}

¡Entiende dos routers y domina Next.js!

En mi caso, el primer proyecto en el que trabajé con Next.js utilizaba App Router.

Después, en otro proyecto tuve que trabajar con Pages Router, y me encontré pensando: "¿Para crear una nueva página debo usar el nombre de archivo index.tsx o page.tsx??"

Aunque el contenido de hoy es solo una pequeña parte de Next.js, investigar nuevamente las diferencias entre App Router y Pages Router me ayudó a organizar mejor mis conocimientos.

Personalmente me encanta la sintaxis de App Router por ser más clara, pero también quiero asegurarme de poder trabajar eficientemente en proyectos con Pages Router.

¡El ideal es comprender Next.js más profundamente y poder elegir el router adecuado según el proyecto o el trabajo que estemos realizando!

Autor de este artículo

Me dedico al desarrollo frontend con enfoque en el marcado, utilizando JavaScript, React y Next.js. ¡Me alegra mucho cuando los sitios en los que he trabajado se publican exitosamente! Mi hobby es tocar la guitarra. Me encantan los gatos y los boniatos🐱🍠

Hiraitch

Ingeniero de frontend / Incorporado en 2022

Ver artículos de este staff

Destacamos por nuestro equipo confiable y nuestra rápida capacidad de respuesta

En Liberogic, nuestro personal experimentado impulsa activamente los proyectos, lo que nos ha ganado una alta evaluación de nuestros clientes.
Nos aseguramos de asignar adecuadamente gerentes de proyecto y directores, manteniendo una ejecución fluida de todo el proyecto. Evitamos aumentos de costos innecesarios mediante asignación completa, distribuyendo recursos estratégicamente según las necesidades, y somos reconocidos por la rapidez en la comprensión de tareas, elaboración de presupuestos y entrega de cotizaciones.

* Tome en cuenta que nuestra empresa no participa activamente en labores de residencia tipo SES.

Puede utilizar prácticamente todas las herramientas principales de gestión de proyectos y chat como Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, Webex, entre otras.

En proyectos grandes que utilizan SES u offshore, ¿tiene dudas o dificultades en cuanto a desafíos técnicos o enfoques?

Casos de Estudio