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.
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
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!
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