Fundamentos Next.js: Components, navegación Link, estilos y tipos de letra.


by Juan Carlos García
20-Abr-2025
(1)
Aprende Next.js desde sus bases fundamentales
Server components y client components
Navegación entre páginas con Link
Estilos en Next.js: CSS Modules, styled-jsx y Tailwind CSS
Post relacionados

Fundamentos Next.js
Fundamentos Next.js: Components, navegación Link, estilos y tipos de letra.
(1)


Curso de Next.js gratuito
Curso de Next.js gratis desde Cero: Domina el Framework de React para aplicaciones web
(1)

next.config.js y variables de entorno en Next.js
Domina next.config.js y variables de entorno en Next.js 15: Configuración esencial
(1)

En el mundo del desarrollo web moderno, Next.js se ha posicionado como uno de los frameworks más populares de React, usado por miles de desarrolladores que trabajan con aplicaciones React, en esta clase té guiará a través de los conceptos esenciales, aprenderás la diferencia entre componentes de cliente y componentes de servidor, como navegar entre páginas a través de Link, personalizar el tipo de fuente en tú página web y dar estilo a tus coponentes.
Tabla de contenido
- 1 Componentes React en Next.js 15: Diferencias Clave y Mejoras
- 2 Ejercicio Práctico: Migrar Componentes a Next.js 15
- 3 Mejoras en Next.js 15 para Componentes
- 4 Recomendaciones claves para el uso de componentes en Next.js
- 5 Navegación Avanzada con el Componente Link en Next.js 15
- 6 Ejercicio Práctico: Implementación Completa
- 7 Optimizaciones Avanzadas
- 8 Manejo de Estilos en Next.js: CSS Modules, styled-jsx y Tailwind CSS
- 9 Ejercicio Práctico: Implementación con TypeScript
- 10 Optimizaciones en Next.js 15
- 11 Gestión de Fuentes o tipos de letra con next/font
Componentes React en Next.js 15: Diferencias Clave y Mejoras
Next.js 15 introduce cambios significativos en cómo trabajamos con componentes React, optimizando el rendimiento y simplificando patrones comunes, estos avances permiten crear aplicaciones más eficientes con menos código manteniendo la flexibilidad de React.
1. Server Components vs Client Components
La principal innovación en Next.js 15 es la distinción clara entre dos tipos de componentes:
Server Components | Client Components |
---|---|
Renderizado en el servidor | Renderizado en el cliente |
No tienen estado ni efectos | Pueden usar useState, useEffect |
Acceso directo a backend | Requieren API routes para datos |
Tamaño bundle cero | Incluidos en el bundle JS |
2. Sintaxis de Componentes en Next.js 15
Los componentes ahora requieren una directiva especial para definir su tipo:
// Server Component (por defecto)
export default function ServerComponent() {
const data = await fetchData() // Fetch directo
return <div>{data}</div>
}
// Client Component (requiere 'use client')
'use client'
export default function ClientComponent() {
const [state, setState] = useState(null)
return <button onClick={() => setState('clicked')}>{state}</button>
}
Ejercicio Práctico: Migrar Componentes a Next.js 15
Paso 1: Convertir un Componente Existente
Componente tradicional (React puro):
import { useState, useEffect } from 'react'
export default function ProductList() {
const [products, setProducts] = useState([])
useEffect(() => {
fetch('/api/products')
.then(res => res.json())
.then(data => setProducts(data))
}, [])
return (
<ul>
{products.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
)
}
Paso 2: Versión Optimizada para Next.js 15
// Server Component
async function ProductList() {
const products = await fetch('https://api.example.com/products')
.then(res => res.json())
return (
<ul>
{products.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
)
}
// Client Component para interactividad
"use client";
import { useState } from "react";
export default function AddToCartButton({ productId }: { productId: number }) {
const [adding, setAdding] = useState(false);
const handleClick = async () => {
setAdding(true);
/**
*Código necesario para agregar el producto al carrito
*/
setAdding(false);
};
return (
<button onClick={handleClick}>
{adding ? "Adding..." : "Add to Cart"}
</button>
);
}
Paso 3: Combinación Óptima
export default function ProductPage() {
return (
<div>
<ProductList />
<AddToCartButton productId={123} />
</div>
)
}
Mejoras en Next.js 15 para Componentes
1. Async/Await en Server Components
Next.js 15 permite usar async/await directamente en componentes:
export default async function UserProfile({ userId:string }) {
const user = await getUser(userId)
const posts = await getPosts(userId)
return (
<div>
<h1>{user.name}</h1>
<PostsList posts={posts} />
</div>
)
}
Recomendaciones claves para el uso de componentes en Next.js
- Usar Server Components para todo el contenido estático o dinámico no interactivo
- Limitar Client Components solo a elementos que necesitan interactividad
- Aprovechar async/await en componentes para código más limpio en la llamdas a la API u obtención de datos
- Organizar componentes en carpetas separadas (
/components/ui
,/components/layout
)
Gracias por tu calificación
(1)
Navegación Avanzada con el Componente Link en Next.js 15
El componente Link en Next.js 15 ha evolucionado para ofrecer un rendimiento superior y características mejoradas para la navegación entre páginas, siendo la piedra angular para crear aplicaciones rápidas y fluidas, este componente ahora incluye prefetching inteligente, transiciones optimizadas y un mejor manejo de rutas dinámicas.
Uso Básico del Componente Link
La implementación fundamental sigue siendo sencilla pero poderosa:
import Link from 'next/link'
export default function Navigation() {
return (
<nav>
<Link href="/about">Sobre Nosotros</Link>
<br />
<Link href="/blog">Blog</Link>
<br />
<Link href="/contact">Contacto</Link>
</nav>
)
}
Mejoras en Next.js 15
La versión 15 introduce optimizaciones significativas:
- Prefetching automático mejorado: Más preciso y eficiente en el uso de recursos, esto es útil, ya que, permite cargar recursos antes de que el usuario los solicite.
- Nuevas props: scroll, prefetch y replace con comportamientos optimizados
- Integración con Server Components: Funcionalidad completa en ambos tipos de componentes
Navegación con Rutas Dinámicas
El manejo de parámetros en rutas dinámicas ha sido simplificado:
import Link from "next/link";
// Ejemplo con TypeScript
export interface ProductParams {
id: number;
name: string;
category: string;
}
export default function ProductList({
products,
}: {
products: ProductParams[];
}) {
return (
<ul>
{products.map((product) => (
<li key={product.id}>
<Link href={`/products/${product.category}`}>{product.category}</Link>
<br />
<Link href={`/products/${product.category}/${product.id}`}>
{product.name}
</Link>
</li>
))}
</ul>
);
}
Ejercicio Práctico: Implementación Completa
Paso 1: Configuración Inicial con TypeScript
Crea un componente de navegación tipado:
// components/Navigation.tsx
import Link from 'next/link'
import { ReactNode } from 'react'
interface NavLink {
href: string
children: ReactNode
className?: string
}
export function NavLink({ href, children, className }: NavLink) {
return (
<Link
href={href}
className={`px-4 py-2 hover:text-blue-500 ${className}`}
prefetch={false} // Desactiva prefetch para este enlace
>
{children}
</Link>
)
}
Paso 2: Navegación Programática con useRouter
Implementa navegación desde código con TypeScript:
// hooks/useNavigation.ts
'use client'
import { useRouter } from 'next/navigation'
import { MouseEvent } from 'react'
export function useNavigation() {
const router = useRouter()
const navigate = (
path: string,
e?: MouseEvent<HTMLAnchorElement>
) => {
e?.preventDefault()
router.push(path)
}
return { navigate }
}
// Uso en componente
// Recuerda los hooks solo pueden ser utilizados en componentes de cliente
const { navigate } = useNavigation()
<button onClick={() => navigate('/dashboard')}>
Ir al Dashboard
</button>
Paso 3: Componente de Breadcrumbs
Ahora con lo que has aprendido, crea el siguiente sistema de migas de pan con rutas dinámicas:
// components/Breadcrumbs.tsx
import Link from "next/link";
export interface BreadcrumbItem {
path: string;
label: string;
}
export default function Breadcrumbs({ items }: { items: BreadcrumbItem[] }) {
return (
<nav className="flex" aria-label="Breadcrumb">
{items.map((item, index) => (
<div key={item.path} className="flex items-center">
{index > 0 && <span className="mx-2">/</span>}
<Link
href={item.path}
className="text-sm hover:underline"
aria-current={index === items.length - 1 ? "page" : undefined}
>
{item.label}
</Link>
</div>
))}
</nav>
);
}
Optimizaciones Avanzadas
Prefetching Inteligente
Next.js 15 analiza el viewport y el hover para prefetch:
<Link
href="/dashboard"
prefetch={true} // Activado por defecto
scroll={false} // Desactiva scroll al top automático
>
Dashboard
</Link>
Gracias por tu calificación
(1)
Manejo de Estilos en Next.js: CSS Modules, styled-jsx y Tailwind CSS
Next.js ofrece múltiples enfoques para gestionar estilos, cada uno con sus propias ventajas y casos de uso ideales, entender estas opciones permite seleccionar la mejor estrategia según las necesidades del proyecto, garantizando un desarrollo eficiente y fácil de mantener.
1. CSS Modules: Estilos Locales por Componente
Los CSS Modules son la solución predeterminada en Next.js para estilos con alcance local, generando nombres de clase únicos automáticamente:
// components/Button.module.css
.primary {
background-color: #2563eb;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
}
// components/Button.tsx
import styles from './Button.module.css'
export function Button({ children }: { children: React.ReactNode }) {
return <button className={styles.primary}>{children}</button>
}
2. styled-jsx: CSS en el Componente
styled-jsx permite escribir CSS directamente dentro de los componentes React:
// components/Card.tsx
"use client";
export function Card({ children }: { children: React.ReactNode }) {
return (
<div className="card">
{children}
<style jsx>{`
.card {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.card:hover {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
`}</style>
</div>
);
}
3. Tailwind CSS: Utilidades First
Tailwind CSS se ha convertido en la opción preferida para muchos proyectos Next.js gracias a su productividad:
// components/Alert.tsx
interface AlertProps {
variant: 'success' | 'error' | 'warning'
children: React.ReactNode
}
export function Alert({ variant, children }: AlertProps) {
const baseClasses = 'p-4 rounded-lg border'
const variantClasses = {
success: 'bg-green-50 border-green-200 text-green-800',
error: 'bg-red-50 border-red-200 text-red-800',
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800'
}
return (
<div className={`${baseClasses} ${variantClasses[variant]}`}>
{children}
</div>
)
}
Ejercicio Práctico: Implementación con TypeScript
Si has seguido este curso desde el inicio no es necesario que hagas este punto, ya que, al crear el proyecto, seleccionamos que deseábamos utilizar Tailwind CSS, por lo que esta configuración ya esta agregada por defecto, pero, por si se te paso indicar que querías agregar Tailwind CSS, te enseño como deberías agregarla a tu proyecto.
Paso 1: Configurar Tailwind CSS
Instala las dependencias necesarias:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
Configura tailwind.config.js
:
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}'
],
theme: {
extend: {},
},
plugins: [],
}
Paso 2: Componente con CSS Modules y TypeScript
// components/ProfileCard.tsx
import styles from './ProfileCard.module.css'
interface ProfileCardProps {
name: string
role: string
avatarUrl: string
}
export function ProfileCard({ name, role, avatarUrl }: ProfileCardProps) {
return (
<div className={styles.card}>
<img src={avatarUrl} alt={name} className={styles.avatar} />
<h3 className={styles.name}>{name}</h3>
<p className={styles.role}>{role}</p>
</div>
)
}
Paso 3: Componente Híbrido (Tailwind + CSS Modules)
// components/PricingCard.tsx
import styles from "./PricingCard.module.css";
interface PricingCardProps {
plan: string;
price: string;
features: string[];
isPopular?: boolean;
}
export function PricingCard({
plan,
price,
features,
isPopular,
}: PricingCardProps) {
return (
<div
className={`relative ${styles.card} ${isPopular ? styles.popular : ""}`}
>
{isPopular && (
<div className="absolute top-0 right-0 bg-blue-500 text-white px-2 py-1 text-xs font-bold rounded-bl">
POPULAR
</div>
)}
<h3 className="text-xl font-bold mb-2">{plan}</h3>
<p className="text-3xl font-bold mb-4">{price}</p>
<ul className="space-y-2 mb-6">
{features.map((feature, index) => (
<li key={index} className="flex items-center">
<svg
className="w-4 h-4 mr-2 text-green-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M5 13l4 4L19 7"
/>
</svg>
{feature}
</li>
))}
</ul>
<button
className={`w-full py-2 px-4 rounded-md font-medium ${
isPopular ? "bg-blue-500 text-white" : "bg-gray-100 text-gray-800"
}`}
>
Seleccionar Plan
</button>
</div>
);
}
Optimizaciones en Next.js 15
1. PurgeCSS Automático
Next.js 15 optimiza automáticamente los estilos eliminando código no utilizado:
- Para Tailwind: Configurado en
tailwind.config.js
- Para CSS Modules: Elimina selectores no usados en producción
2. PostCSS Integrado
Configuración avanzada en postcss.config.js
:
module.exports = {
plugins: {
'postcss-flexbugs-fixes': {},
'postcss-preset-env': {
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3,
features: {
'custom-properties': false
}
}
}
}
3. Soporte para Sass
Usa Sass con CSS Modules instalando el paquete:
yarn add -D sass
// components/Button.module.scss
$blue: #2563eb;
$red: #aa3939;
.primary {
background-color: $blue;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
&:hover {
background-color: $red;
}
}
4. Estilos Globales
Crea estilos globales en app/globals.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--color-primary: 37 99 235;
}
html {
scroll-behavior: smooth;
}
}
@layer components {
.btn-primary {
@apply bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded;
}
}
Gracias por tu calificación
(1)
Gestión de Fuentes o tipos de letra con next/font
Optimización automática de fuentes:
// lib/fonts.ts
import { Inter, Roboto_Mono } from 'next/font/google'
export const inter = Inter({
subsets: ['latin'],
variable: '--font-inter',
display: 'swap',
weight: ['400', '500', '700'] // Solo incluye los pesos necesarios
})
export const robotoMono = Roboto_Mono({
subsets: ['latin'],
variable: '--font-roboto-mono',
adjustFontFallback: false // Desactiva fuentes de fallback si no son necesarias
})
/*
* Comentario:
* - subsets reduce el tamaño del archivo de fuente
* - display: swap evita layout shift
* - variable permite usar CSS variables
*/
Excelente, eres un campeón por haber llegado hasta el final, espero te haya gustado y hayas aprendido cosas nuevas, nos vemos en la siguiente clase.
Gracias por tu calificación
(1)
🧐 Autoevaluación: Fundamentos Next.js
¿Cuál es la principal diferencia entre Client Components y Server Components en Next.js 15?
¿Qué atributo del componente Link de Next.js es esencial para mejorar el rendimiento en la navegación?
¿Cuál es la forma recomendada de aplicar estilos en Next.js 15 para mantener un buen rendimiento?

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.