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
-
Renderizado Híbrido
- Server-Side Rendering (SSR)
- Static Site Generation (SSG)
- Client-Side Rendering (CSR)
- Incremental Static Regeneration (ISR)
-
Optimizaciones Automáticas
- Optimización de imágenes
- Font optimization
- Script optimization
- Zero config
-
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
Estructura del Proyecto
├── app/
│ ├── layout.tsx
│ ├── page.tsx
│ └── globals.css
├── public/
│ └── images/
├── components/
│ └── ui/
├── lib/
├── next.config.js
└── package.json
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>
);
}
Rutas Dinámicas
// app/blog/[slug]/page.tsx
export default function BlogPost({ params }: { params: { slug: string } }) {
return (
<article>
<h1>Post: {params.slug}</h1>
</article>
);
}
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>
);
}
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>
);
}
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>
);
}
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 }
);
}
}
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
/>
);
}
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>
);
}
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>
);
}
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>
);
}
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>
);
}
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*',
};
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();
});
});
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;
Mejores Prácticas
- Organización del Código
app/
├── (auth)/
│ ├── login/
│ └── register/
├── (dashboard)/
│ ├── profile/
│ └── settings/
└── (marketing)/
├── about/
└── contact/
- 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>
);
}
- 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>
);
}
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! 🚀
Top comments (0)