Volver a Next.js Básico

Enrutamiento Basado en Archivos

El App Router de Next.js usa el sistema de archivos para definir rutas. Cada page.tsx dentro de app/ se convierte en una URL públicamente accesible.

Convenciones de Rutas

ArchivoURL
app/page.tsx/
app/sobre/page.tsx/sobre
app/blog/[slug]/page.tsx/blog/mi-post
app/tienda/[...ruta]/page.tsx/tienda/a/b/c
app/(marketing)/page.tsx/ (grupo, sin impacto en URL)

Rutas Dinámicas

// app/blog/[slug]/page.tsx interface Props { params: Promise<{ slug: string }>; } export default async function BlogPost({ params }: Props) { const { slug } = await params; const post = await obtenerPost(slug); return ( <article> <h1>{post.titulo}</h1> <div dangerouslySetInnerHTML={{ __html: post.contenido }} /> </article> ); } // Generar rutas estáticas en tiempo de compilación export async function generateStaticParams() { const posts = await obtenerTodosPosts(); return posts.map(post => ({ slug: post.slug })); }

Layouts Anidados

// app/blog/layout.tsx — envuelve todas las rutas /blog/* export default function BlogLayout({ children, }: { children: React.ReactNode; }) { return ( <div className="flex"> <aside className="w-64"> <BarraLateralBlog /> </aside> <main className="flex-1">{children}</main> </div> ); }
import Link from 'next/link'; import { useRouter } from 'next/navigation'; // Declarativa — preferida export function NavLinks() { return ( <nav> <Link href="/">Inicio</Link> <Link href="/sobre">Sobre mí</Link> <Link href="/blog/mi-post" prefetch={false}>Post</Link> </nav> ); } // Programática (solo en Componentes de Cliente) 'use client'; export function Volver() { const router = useRouter(); return <button onClick={() => router.back()}>← Volver</button>; }

Estados de Carga y Error

// app/blog/loading.tsx — mostrado mientras la página carga export default function Cargando() { return <div className="skeleton">Cargando posts...</div>; } // app/blog/error.tsx — mostrado cuando ocurre un error 'use client'; export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return ( <div> <h2>¡Algo salió mal!</h2> <p>{error.message}</p> <button onClick={reset}>Intentar de nuevo</button> </div> ); }

Grupos de Rutas

Usa paréntesis (nombre) para organizar rutas sin afectar la URL:

app/
├── (marketing)/
│   ├── layout.tsx      # Layout para marketing
│   ├── page.tsx        # /
│   └── sobre/page.tsx  # /sobre
└── (dashboard)/
    ├── layout.tsx      # Layout del dashboard (protegido con auth)
    └── dashboard/page.tsx  # /dashboard