DEV Community

Cover image for Next.js: La Guía Definitiva del Framework React más Popular
Joaquín Gutiérrez
Joaquín Gutiérrez

Posted on

Next.js: La Guía Definitiva del Framework React más Popular

Next.js se ha convertido en el framework de React más popular para construir aplicaciones web modernas. Con su enfoque en la renderización del lado del servidor (SSR), generación estática, y una excelente experiencia de desarrollo, Next.js ofrece todo lo necesario para construir aplicaciones web escalables y de alto rendimiento.

¿Por qué Next.js?

Características Principales

  1. Renderizado Híbrido

    • Server-Side Rendering (SSR)
    • Static Site Generation (SSG)
    • Client-Side Rendering (CSR)
    • Incremental Static Regeneration (ISR)
  2. Optimizaciones Automáticas

    • Optimización de imágenes
    • Font optimization
    • Script optimization
    • Zero config
  3. Developer Experience

    • Fast Refresh
    • TypeScript Support
    • File-system routing
    • API Routes

Primeros Pasos

Creación de un Proyecto

npx create-next-app@latest mi-proyecto
cd mi-proyecto
npm run dev
Enter fullscreen mode Exit fullscreen mode

Estructura del Proyecto

├── app/
│   ├── layout.tsx
│   ├── page.tsx
│   └── globals.css
├── public/
│   └── images/
├── components/
│   └── ui/
├── lib/
├── next.config.js
└── package.json
Enter fullscreen mode Exit fullscreen mode

Routing en Next.js 14

Páginas Básicas

// app/page.tsx
export default function Home() {
  return (
    <main>
      <h1>Bienvenidos a Next.js</h1>
    </main>
  );
}
Enter fullscreen mode Exit fullscreen mode

Rutas Dinámicas

// app/blog/[slug]/page.tsx
export default function BlogPost({ params }: { params: { slug: string } }) {
  return (
    <article>
      <h1>Post: {params.slug}</h1>
    </article>
  );
}
Enter fullscreen mode Exit fullscreen mode

Layout Compartido

// app/layout.tsx
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <nav>
          {/* Navegación común */}
        </nav>
        {children}
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

Data Fetching

Server Components

// app/posts/page.tsx
async function getPosts() {
  const res = await fetch('https://api.ejemplo.com/posts', {
    next: { revalidate: 3600 } // Revalidar cada hora
  });
  return res.json();
}

export default async function Posts() {
  const posts = await getPosts();

  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Static Generation

// app/posts/[id]/page.tsx
export async function generateStaticParams() {
  const posts = await getPosts();

  return posts.map((post) => ({
    id: post.id.toString(),
  }));
}

export default async function Post({ params }: { params: { id: string } }) {
  const post = await getPost(params.id);

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  );
}
Enter fullscreen mode Exit fullscreen mode

API Routes

// app/api/posts/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  try {
    const posts = await getPosts();
    return NextResponse.json(posts);
  } catch (error) {
    return NextResponse.json(
      { error: 'Error al obtener posts' },
      { status: 500 }
    );
  }
}

export async function POST(request: Request) {
  try {
    const data = await request.json();
    const newPost = await createPost(data);
    return NextResponse.json(newPost, { status: 201 });
  } catch (error) {
    return NextResponse.json(
      { error: 'Error al crear post' },
      { status: 500 }
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Optimizaciones

Imágenes

import Image from 'next/image';

export default function Profile() {
  return (
    <Image
      src="/perfil.jpg"
      alt="Foto de perfil"
      width={500}
      height={300}
      priority
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

Fonts

import { Roboto } from 'next/font/google';

const roboto = Roboto({
  weight: ['400', '700'],
  subsets: ['latin'],
  display: 'swap',
});

export default function Layout({ children }) {
  return (
    <div className={roboto.className}>
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Manejo de Estado

Client Components

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Contador: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Incrementar
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Estilización

CSS Modules

// components/Button.tsx
import styles from './Button.module.css';

export default function Button({ children }) {
  return (
    <button className={styles.button}>
      {children}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

Tailwind CSS

export default function Card({ title, content }) {
  return (
    <div className="p-6 max-w-sm mx-auto bg-white rounded-xl shadow-lg flex items-center space-x-4">
      <div>
        <div className="text-xl font-medium text-black">{title}</div>
        <p className="text-gray-500">{content}</p>
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Middleware

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Verificar autenticación
  const token = request.cookies.get('token');

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: '/dashboard/:path*',
};
Enter fullscreen mode Exit fullscreen mode

Testing

// __tests__/Home.test.tsx
import { render, screen } from '@testing-library/react';
import Home from '@/app/page';

describe('Home', () => {
  it('renders a heading', () => {
    render(<Home />);
    const heading = screen.getByRole('heading', { level: 1 });
    expect(heading).toBeInTheDocument();
  });
});
Enter fullscreen mode Exit fullscreen mode

Deployment

Configuración de Producción

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    domains: ['tu-dominio.com'],
  },
  async redirects() {
    return [
      {
        source: '/old-page',
        destination: '/new-page',
        permanent: true,
      },
    ];
  },
};

module.exports = nextConfig;
Enter fullscreen mode Exit fullscreen mode

Mejores Prácticas

  1. Organización del Código
   app/
   ├── (auth)/
   │   ├── login/
   │   └── register/
   ├── (dashboard)/
   │   ├── profile/
   │   └── settings/
   └── (marketing)/
       ├── about/
       └── contact/
Enter fullscreen mode Exit fullscreen mode
  1. Error Handling
   // app/error.tsx
   'use client';

   export default function Error({
     error,
     reset,
   }: {
     error: Error & { digest?: string };
     reset: () => void;
   }) {
     return (
       <div>
         <h2>¡Algo salió mal!</h2>
         <button onClick={() => reset()}>Intentar de nuevo</button>
       </div>
     );
   }
Enter fullscreen mode Exit fullscreen mode
  1. Loading States
   // app/loading.tsx
   export default function Loading() {
     return (
       <div className="flex items-center justify-center">
         <div className="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900" />
       </div>
     );
   }
Enter fullscreen mode Exit fullscreen mode

Conclusión

Next.js 14 ofrece:

  • Rendimiento excepcional
  • Excelente DX (Developer Experience)
  • Escalabilidad
  • Flexibilidad en el renderizado
  • Integración perfecta con React

Es la elección ideal para:

  • Aplicaciones web empresariales
  • Sitios de e-commerce
  • Aplicaciones SaaS
  • Sitios de contenido dinámico

Recursos Adicionales

¿Estás usando Next.js en tus proyectos? ¿Qué características te parecen más útiles? ¡Comparte tu experiencia en los comentarios! 🚀

nextjs #react #webdev #javascript

Top comments (0)