Aprende Next.js con Layouts avanzados y Data Fetching optimizado

Domina Layouts y Data Fetching en Next.js 15

Continuando con este Curso de Next.js desde cero, descubrirás cómo dominar dos pilares fundamentales de Next.js 15: los Layouts avanzados y el Data Fetching optimizado.

Este curso te enseñará a estructurar tus proyectos profesionalmente usando el sistema de Layouts anidados de Next.js 15, además de implementar estrategias modernas de Data Fetching que mejorarán significativamente el rendimiento de tu Aplicación web con Next.js.

Al finalizar, serás capaz de configurar rutas complejas, manejar estados de carga elegantes y optimizar el SEO en Next.js mediante la precarga inteligente de datos. Perfecto para quienes buscan Aprender Next.js de manera profesional.

InicionextjsLayouts y Data Fetching Next.js
Domina Layouts y Data Fetching en Next.js 15
Domina Layouts y Data Fetching en Next.js 15

by Juan Carlos García

12-My-2025

(1)

Suscribirme al canal:

Dominando los Layouts en Next.js 15: Estructura y Reutilización

En Next.js desde, los layouts representan uno de los conceptos más poderosos para organizar tu aplicación, te permiten crear estructuras reutilizables que envuelven tus páginas con componentes comunes como headers, footers o sidebars.

¿Qué son los Layouts en Next.js?

Los layouts son componentes especiales que envuelven las páginas de tu aplicación, preservando el DOM entre navegaciones, esto es fundamental para Optimización de rendimiento en Next.js, ya que, evita renderizados innecesarios.


// Ejemplo básico de layout
// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang='es'>
      <body className='min-h-screen bg-gray-50'>
        <Header />
        <main className='container mx-auto py-8'>{children}</main>
        <Footer />
      </body>
    </html>
  )
}

Layouts anidados y jerarquías

Una de las Características de Next.js más útiles es la capacidad de anidar layouts, creando jerarquías que se adaptan a diferentes secciones de tu aplicación.


// Estructura de directorios
app/
  layout.tsx          // Layout raíz
  dashboard/
    layout.tsx        // Layout específico para dashboard
    page.tsx
  settings/
    layout.tsx        // Layout específico para settings
    page.tsx

Mejores prácticas para layouts

Al trabajar con layouts en tu Configuración de Next.js, sigue estas recomendaciones:

  • Mantén los layouts simples: Cada layout debe tener una responsabilidad clara
  • Organiza por rutas: Agrupa layouts con sus páginas relacionadas

Optimizando layouts para SEO

Los layouts son ideales para implementar estrategias de SEO en Next.js de manera centralizada:


// app/layout.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Mi Aplicación',
  description: 'Bienvenido a mi aplicación Next.js',
  keywords: ['Next.js', 'React', 'JavaScript'],
  openGraph: {
    images: '/og-image.png',
  },
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang='es'>
      <body>
        {children}
      </body>
    </html>
  )
}

Para comenzar a usar layouts en tu proyecto, asegúrate de tener una Instalación de Next.js actualizada (versión 13+), los layouts son una característica fundamental del App Router que revoluciona cómo estructuramos nuestras aplicaciones en Next.js 15.

Diseño de páginas web EWebik

Implementación de Layouts Compartidos y Anidados en Next.js 15

En este Curso de Next.js desde cero, vamos a crear un sistema completo de layouts que muestra cómo estructurar una aplicación profesional con un layout principal y layouts secundarios especializados.

Estructura del Proyecto

Primero, definamos la estructura de directorios para nuestro sistema de layouts:


app/
├── layout.tsx              # Layout principal
├── page.tsx                # Página home
├── marketing/
│   ├── layout.tsx          # Layout para páginas de marketing
│   ├── page.tsx            # Home de marketing
│   └── about/
│       └── page.tsx        # Página about
└── app/
    ├── layout.tsx          # Layout para área de aplicación
    ├── dashboard/
    │   └── page.tsx       # Dashboard principal
    └── settings/
        └── page.tsx       # Página de configuraciones

Layout Principal (Root Layout)

El layout principal envuelve toda la aplicación y contiene elementos compartidos como el header y footer:


// app/layout.tsx
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";

import "@/styles/globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
        <header className="bg-blue-600 text-white p-4">
          <h1 className="text-xl font-bold">Mi Aplicación</h1>
        </header>

        <main className="container mx-auto py-8">{children}</main>

        <footer className="bg-gray-800 text-white p-4 mt-8">
          <p>© 2023 Mi Aplicación - Todos los derechos reservados</p>
        </footer>
      </body>
    </html>
  );
}

Layout de Marketing

Este layout se usa para las páginas públicas de marketing y añade un menú específico:


// app/marketing/layout.tsx
export default function MarketingLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className='marketing-layout'>
      <nav className='bg-white shadow-sm p-4'>
        <div className='flex space-x-6'>
          <a href='/marketing' className='text-blue-600'>Inicio</a>
          <a href='/marketing/about' className='text-blue-600'>Nosotros</a>
          <a href='/contact' className='text-blue-600'>Contacto</a>
        </div>
      </nav>
      
      <div className='max-w-4xl mx-auto px-4 py-8'>
        {children}
      </div>
    </div>
  )
}

Layout de Aplicación

Este layout es para el área privada de la aplicación e incluye una sidebar:


// app/app/layout.tsx
export default function AppLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex min-h-screen">
      <aside className="w-64 bg-gray-800 text-white p-4">
        <h2 className="text-xl font-bold mb-6">Menú</h2>
        <nav className="space-y-2">
          <a
            href="/app/dashboard"
            className="block py-2 px-4 hover:bg-gray-700 rounded"
          >
            Dashboard
          </a>
          <a
            href="/app/settings"
            className="block py-2 px-4 hover:bg-gray-700 rounded"
          >
            Configuración
          </a>
        </nav>
      </aside>

      <div className="flex-1 p-8">{children}</div>
    </div>
  );
}

Página de Marketing

// app/marketing/page.tsx
export default function MarketingPage() {
  return (
    <div>
      <h1 className='text-3xl font-bold mb-4'>Marketing - EWebik</h1>
      <p className='text-lg'>
         Creación de páginas web profesionales.
      </p>
    </div>
  )
}

Página de Marketing (About)


// app/marketing/about/page.tsx
export default function AboutPage() {
  return (
    <div>
      <h1 className='text-3xl font-bold mb-4'>EWebik</h1>
      <p className='text-lg'>
         Creación de páginas web profesionales y cursos gratuitos de programación, base de datos y desarrollo web.
      </p>
    </div>
  )
}

Página de App

// app/app/page.tsx
export default function AppPage() {
  return (
    <div>
      <h1 className="text-3xl font-bold mb-4">APP</h1>
      <p className="text-lg">Bienvenido</p>
    </div>
  );
}

Página de Dashboard


// app/app/dashboard/page.tsx
export default function DashboardPage() {
  return (
    <div>
      <h1 className="text-2xl font-bold mb-6">Mi Dashboard - EWebik</h1>
      <div className="grid grid-cols-3 gap-4">
        <div className="bg-blue-500 p-4 rounded-lg text-center">
          Estadística 1
        </div>
        <div className="bg-green-500 p-4 rounded-lg text-center">
          Estadística 2
        </div>
        <div className="bg-yellow-500 p-4 rounded-lg text-center">
          Estadística 3
        </div>
      </div>
    </div>
  );
}

Página de Settings

// app/app/settings/page.tsx
export default function SettingsPage() {
  return (
    <div>
      <h1 className='text-3xl font-bold mb-4'>Settings</h1>
      <p className='text-lg'>
         Ajustes principales
      </p>
    </div>
  )
}

Mejores Prácticas para Layouts Anidados

Al trabajar con layouts en tu Aplicación web con Next.js, considera estas recomendaciones:

  • Jerarquía clara: Organiza los layouts de más general a más específico
  • Estilos encapsulados: Usa módulos CSS para evitar conflictos
  • Props consistentes: Mantén la misma interfaz para children en todos los layouts
  • Metadata dinámica: Aprovecha generateMetadata para SEO en cada nivel
  • Performance: Usa Server Components en layouts cuando sea posible

Este sistema de layouts anidados te permite crear aplicaciones complejas manteniendo un código organizado y escalable, una habilidad esencial para Aprender Next.js.

Diseño de páginas web EWebik

Data Fetching en Next.js 15: Técnicas Avanzadas y Optimización

Ahora exploraremos las poderosas capacidades de obtención de datos de Next.js 15, un conocimiento esencial para construir Aplicaciones web con Next.js modernas y eficientes.

1. Fundamentos de Data Fetching en Next.js 15

Next.js 15 ofrece múltiples estrategias para obtener datos, cada una diseñada para casos de uso específicos:

  • Server Components: La forma recomendada para la mayoría de casos
  • Route Handlers: Para crear endpoints API
  • Client-side Data Fetching: Cuando necesitas datos dinámicos en el cliente

2. Fetching en Server Components

La forma más eficiente de obtener datos en Next.js 15 es directamente en componentes de servidor:


// app/blog/page.tsx
async function getBlogPosts() {
  const res = await fetch('https://api.example.com/posts')
  if (!res.ok) throw new Error('Failed to fetch posts')
  return res.json()
}

export default async function BlogPage() {
  const posts = await getBlogPosts()
  
  return (
    <div className='blog-container'>
      {posts.map(post => (
        <article key={post.id} className='post-card'>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  )
}

3. Optimización del Fetching

Next.js 15 incluye mejoras significativas en el fetching automático:


// Ejemplo con revalidación cada hora
async function getProducts() {
  const res = await fetch('https://api.example.com/products', {
    next: { revalidate: 3600 } // Revalida cada hora
  })
  return res.json()
}

4. Route Handlers (API Routes)

Crea endpoints API directamente en tu aplicación:


// app/api/products/route.ts
export async function GET() {
  const products = await db.products.findMany()
  return Response.json(products)
}

export async function POST(request: Request) {
  const data = await request.json()
  const newProduct = await db.products.create({ data })
  return Response.json(newProduct, { status: 201 })
}

5. Ejercicio Práctico: Blog con Data Fetching

Implementemos un blog completo usando las técnicas de Next.js 15:

Estructura de archivos


app/
├── blog/
│   │   
│   └── page.tsx
└── api/
    └── posts/
        └── route.ts

API Route


// app/api/posts/route.ts
import { NextResponse } from 'next/server'
import db from '@/lib/db'

export async function GET() {
  try {
    const posts = await db.post.findMany({
      select: {
        id: true,
        title: true,
        slug: true,
        createdAt: true
      },
      orderBy: { createdAt: 'desc' }
    })
    return NextResponse.json(posts)
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch posts' },
      { status: 500 }
    )
  }
}

Página principal del blog


// app/blog/page.tsx

import Link from "next/link";

interface Posts {
  id: string;
  title: string;
  slug: string;
  createdAt: string;
}

export default async function BlogPage() {
  const posts: Posts[] = await fetch("http://localhost:3000/api/posts", {
    next: { tags: ["posts"], revalidate: 3600 },
  }).then((res) => res.json());

  return (
    <div className="max-w-4xl mx-auto py-8">
      <h1 className="text-3xl font-bold mb-8">Blog</h1>
      <div className="grid gap-8">
        {posts.map((post) => (
          <article key={post.id} className="border-b pb-6">
            <h2 className="text-2xl font-semibold">{post.title}</h2>
            <p className="text-gray-600 mt-2">{post.createdAt}</p>
            <Link href={post.slug} className="text-xl font-bold text-red-400">
              Ver mas
            </Link>
          </article>
        ))}
      </div>
    </div>
  );
}

Mejores Prácticas data fetching

  • Usa Server Components siempre que sea posible
  • Implementa revalidación para datos dinámicos
  • Centraliza las llamadas API en archivos separados
  • Maneja errores adecuadamente
  • Usa loading states para mejor UX
Diseño de páginas web EWebik

🧐 Autoevaluación: Layouts y Data Fetching Next.js

¿Cuál es la principal ventaja de usar Server Components para Data Fetching en Next.js 15?

¿Cómo se puede compartir un Layout entre múltiples páginas en Next.js 15?

¿Qué propiedad del objeto options en fetch() permite a Next.js 15 cachear y revalidar datos automáticamente?

Juan Carlos

Juan Carlos García

Desarrollador de software / SEO / Ing. eléctrico - electrónico UNAM

Durante años he desarrollado plataformas dedicadas al rastreo satelital y varios sitios web que se encuentran en la primera página de Google, y hoy quiero compartir contigo lo que se en tecnologías como: Node JS, PHP, C# y Bases de datos.

Si quieres apoyarme sígueme en mis redes sociales y suscríbete a mi canal de YouTube.

© 2025 EWebik

En sitio utilizamos cookies propias y de terceros, con fines de análisis y para contenido publicitario. Revisa nuestra Política de Cookies para más información. Si deseas aceptar todas las cookies da clic en