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

InicionextjsFundamentos Next.js
Fundamentos Next.js: Components, navegación Link, estilos y tipos de letra.
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

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

Layouts y Data Fetching Next.js

Layouts y Data Fetching Next.js

Domina Layouts y Data Fetching en Next.js 15

Curso de Next.js gratuito

Curso de Next.js gratuito

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

next.config.js y variables de entorno en Next.js

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

ISR y Server Actions Next.js

ISR y Server Actions Next.js

Domina SSR, ISR y Server Actions en Next.js 15

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.

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 ComponentsClient Components
Renderizado en el servidorRenderizado en el cliente
No tienen estado ni efectosPueden usar useState, useEffect
Acceso directo a backendRequieren API routes para datos
Tamaño bundle ceroIncluidos 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)

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.

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

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>

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;
  }
}

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.

🧐 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

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