Saltar al contenido

Clase 29 - React - Introducción

#react #vite #html

🚀 Ejemplo Paso a Paso - De HTML Vanilla a React

🧱 HTML Tradicional - El Punto de Partida

Comencemos con un ejemplo simple de HTML que muestra tarjetas de productos:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tienda - HTML Tradicional</title>
<style>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
margin: 10px 0;
background: #f9f9f9;
}
.card h3 {
margin-top: 0;
color: #333;
}
.card p {
color: #666;
margin: 10px 0;
}
.price {
font-size: 1.2em;
font-weight: bold;
color: #e74c3c;
}
</style>
</head>
<body>
<div class="container">
<h1>Nuestra Tienda</h1>
<!-- Tarjeta 1 -->
<div class="card">
<h3>Laptop Gaming</h3>
<p>Potente laptop para gaming con RTX 3060</p>
<p class="price">$1,299</p>
</div>
<!-- Tarjeta 2 -->
<div class="card">
<h3>Mouse Inalámbrico</h3>
<p>Mouse ergonómico con sensor óptico</p>
<p class="price">$45</p>
</div>
<!-- Tarjeta 3 -->
<div class="card">
<h3>Teclado Mecánico</h3>
<p>Teclado con switches Cherry MX</p>
<p class="price">$89</p>
</div>
</div>
</body>
</html>

🤔 JavaScript Vanilla - Lo Engorroso que se Vuelve

Ahora imaginemos que queremos hacer esto dinámico con JavaScript vanilla:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tienda - JavaScript Vanilla</title>
<style>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
margin: 10px 0;
background: #f9f9f9;
}
.card h3 {
margin-top: 0;
color: #333;
}
.card p {
color: #666;
margin: 10px 0;
}
.price {
font-size: 1.2em;
font-weight: bold;
color: #e74c3c;
}
</style>
</head>
<body>
<div class="container">
<h1>Nuestra Tienda</h1>
<div id="products-container"></div>
</div>
<script>
// Datos de productos
const products = [
{
id: 1,
name: "Laptop Gaming",
description: "Potente laptop para gaming con RTX 3060",
price: 1299
},
{
id: 2,
name: "Mouse Inalámbrico",
description: "Mouse ergonómico con sensor óptico",
price: 45
},
{
id: 3,
name: "Teclado Mecánico",
description: "Teclado con switches Cherry MX",
price: 89
}
];
// Función para crear una tarjeta (¡Muy engorrosa!)
function createCard(producto) {
// Crear el contenedor principal
const card = document.createElement('div');
card.className = 'card';
// Crear el título
const title = document.createElement('h3');
title.textContent = producto.name;
// Crear la descripción
const description = document.createElement('p');
description.textContent = producto.description;
// Crear el precio
const price = document.createElement('p');
price.className = 'price';
price.textContent = `$${producto.price}`;
// Ensamblar todo
card.appendChild(title);
card.appendChild(description);
card.appendChild(price);
return card;
}
// Función para renderizar todos los productos
function renderProducts() {
const container = document.getElementById('products-container');
// Limpiar contenedor
container.innerHTML = '';
// Crear y añadir cada tarjeta
products.forEach(product => {
const card = createCard(product);
container.appendChild(card);
});
}
// Renderizar al cargar la página
document.addEventListener('DOMContentLoaded', renderProducts);
</script>
</body>
</html>

Problemas evidentes:

  • Mucho código repetitivo para crear elementos.
  • Difícil de mantener y leer.
  • Propenso a errores.
  • No hay separación clara de responsabilidades.
  • Cada cambio requiere manipular el DOM manualmente.

⚛️ Introduciendo React con CDN

Ahora veamos cómo React simplifica esto. Primero, agreguemos React via CDN:

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tienda - React con CDN</title>
<style>
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
margin: 10px 0;
background: #f9f9f9;
}
.card h3 {
margin-top: 0;
color: #333;
}
.card p {
color: #666;
margin: 10px 0;
}
.price {
font-size: 1.2em;
font-weight: bold;
color: #e74c3c;
}
</style>
</head>
<body>
<div id="root"></div>
<!-- React CDN -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Babel para transformar JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// Datos de productos (igual que antes)
const products = [
{
id: 1,
name: "Laptop Gaming",
description: "Potente laptop para gaming con RTX 3060",
price: 1299
},
{
id: 2,
name: "Mouse Inalámbrico",
description: "Mouse ergonómico con sensor óptico",
price: 45
},
{
id: 3,
name: "Teclado Mecánico",
description: "Teclado con switches Cherry MX",
price: 89
}
];
// Componente Card - ¡Mucho más limpio!
function Card({ name, description, price }) {
return (
<div className="card">
<h3>{name}</h3>
<p>{description}</p>
<p className="price">${price}</p>
</div>
);
}
// Componente principal
function App() {
return (
<div className="container">
<h1>Nuestra Tienda</h1>
{products.map(product => (
<Card
key={product.id}
name={product.name}
description={product.description}
price={product.price}
/>
))}
</div>
);
}
// Renderizar la aplicación
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>

Ventajas inmediatas:

  • Código mucho más limpio y legible
  • Reutilización fácil del componente Card
  • Separación clara de responsabilidades
  • Sintaxis declarativa (describes QUÉ quieres, no CÓMO)

⭐ De HTML a React - Conceptos Fundamentales

🧱 HTML tradicional y sus limitaciones

HTML estructura el contenido de la web. Sin embargo, a medida que nuestras aplicaciones crecen, HTML por sí solo se vuelve difícil de mantener.

index.html
<section>
<h1>Hola, mundo</h1>
<p>Bienvenidos a mi sitio web.</p>
</section>

Problemas frecuentes:

  • No tiene lógica integrada
  • No hay reutilización de estructuras
  • Requiere muchas líneas de código para modificar o actualizar información
  • Se vuelve complejo mantener consistencia visual y funcional
  • Manipulación manual del DOM propensa a errores

⚛️ React: declaración de intenciones

React permite escribir código declarativo, componetizado y reactivo, donde cada parte de la interfaz es un componente autónomo.

App.jsx
function App() {
return (
<section>
<h1>Hola, mundo</h1>
<p>Bienvenidos a mi sitio web.</p>
</section>
);
}

✨ Ventajas de pasar de HTML a React

  • Separación lógica por componentes: Cada parte de la UI es independiente
  • Reutilización y organización del código: Escribe una vez, usa en múltiples lugares
  • Mantenimiento y escalabilidad superiores: Más fácil de mantener proyectos grandes
  • Mejores flujos de trabajo con herramientas modernas: Hot reload, debugging, etc.
  • Facilita pruebas unitarias y testeo visual: Cada componente puede probarse por separado

🏋️ La importancia de la componetización

🤔 ¿Qué es un componente?

Un componente es una función de JavaScript que devuelve JSX (una descripción de la interfaz de usuario). Piensa en él como una pieza reutilizable de código que encapsula tanto la estructura (HTML) como la lógica (JavaScript) de una parte específica de tu aplicación.

function Greeting() {
return <h1>¡Hola desde React!</h1>;
}

Características de un buen componente:

  • Tiene una responsabilidad específica.
  • Es reutilizable.
  • Recibe datos a través de props.
  • Puede tener su propio estado interno.
  • Devuelve JSX válido.

🎯 ¿Qué son las Props?

Las props (propiedades) son argumentos que se pasan a los componentes de React. Son como parámetros de función que permiten que los componentes sean dinámicos y reutilizables.

// Definición del componente que recibe props
function Card({ title, content, author, date }) {
return (
<article className="card">
<h2>{title}</h2>
<p>{content}</p>
<footer>
<small>Por {author} el {date}</small>
</footer>
</article>
);
}
// Uso del componente con props
function App() {
return (
<div>
<Card
title="Aprendiendo React"
content="React es una librería increíble para crear interfaces de usuario."
author="Juan Pérez"
date="15 de julio, 2025"
/>
<Card
title="CSS Modules"
content="Los CSS Modules nos ayudan a escribir estilos modulares."
author="Ana García"
date="14 de julio, 2025"
/>
</div>
);
}

Características importantes de las props:

  • Son inmutables (no se pueden modificar dentro del componente)
  • Fluyen unidireccionalmente (de padre a hijo)
  • Pueden ser de cualquier tipo: strings, numbers, arrays, objects, functions.
  • Se acceden como propiedades del objeto props o mediante destructuring.

✨ Componetización efectiva

Principios fundamentales:

  1. Divide y vencerás: Secciona tu interfaz en partes reutilizables.
  2. Responsabilidad única: Cada componente debe tener una sola responsabilidad.
  3. Nombres descriptivos: Usa nombres que describan claramente qué hace el componente.
  4. Reutilización: Diseña componentes que puedan usarse en diferentes contextos.
// ❌ Componente que hace demasiadas cosas
function CompletePage() {
return (
<div>
<header>
<nav>
<ul>
<li><a href="/">Inicio</a></li>
<li><a href="/about">Acerca</a></li>
<li><a href="/contact">Contacto</a></li>
</ul>
</nav>
</header>
<main>
<h1>Bienvenidos</h1>
<article>
<h2>Artículo 1</h2>
<p>Contenido del artículo...</p>
</article>
<article>
<h2>Artículo 2</h2>
<p>Contenido del artículo...</p>
</article>
</main>
<footer>
<p>&copy; 2025 Mi Sitio Web</p>
</footer>
</div>
);
}
// ✅ Componentes bien estructurados
function Navigation() {
return (
<nav>
<ul>
<li><a href="/">Inicio</a></li>
<li><a href="/about">Acerca</a></li>
<li><a href="/contact">Contacto</a></li>
</ul>
</nav>
);
}
function Header() {
return (
<header>
<Navigation />
</header>
);
}
function Article({ title, content }) {
return (
<article>
<h2>{title}</h2>
<p>{content}</p>
</article>
);
}
function Footer() {
return (
<footer>
<p>&copy; 2025 Mi Sitio Web</p>
</footer>
);
}
function App() {
return (
<div>
<Header />
<main>
<h1>Bienvenidos</h1>
<Article
titulo="Artículo 1"
contenido="Contenido del artículo..."
/>
<Article
titulo="Artículo 2"
contenido="Contenido del artículo..."
/>
</main>
<Footer />
</div>
);
}

🌱 Beneficios de la componetización

  • Legibilidad: Código más fácil de leer y entender
  • Mantenimiento: Cambios localizados sin afectar otras partes
  • Reutilización: Usa el mismo componente en diferentes lugares
  • Colaboración: Equipos pueden trabajar en componentes independientes
  • Rendimiento: React puede optimizar el renderizado por componente
  • Testeo: Cada componente puede probarse de forma aislada

🎨 CSS Modules: Estilos Modulares y Encapsulados

🤔 ¿Qué son los CSS Modules?

Los CSS Modules son una forma de escribir CSS donde los nombres de las clases son locales por defecto. Esto significa que no hay conflictos entre estilos de diferentes componentes, ya que cada clase se convierte en un identificador único.

Características principales:

  • Encapsulación: Los estilos solo afectan al componente donde se importan
  • No hay conflictos: Los nombres de clase son únicos automáticamente
  • Composición: Puedes componer estilos fácilmente
  • Compatibilidad: Funciona con CSS normal, no necesitas aprender nueva sintaxis

📁 Estructura de archivos con CSS Modules

src/
├── components/
│ ├── Button/
│ │ ├── Button.jsx
│ │ └── Button.module.css
│ ├── Card/
│ │ ├── Card.jsx
│ │ └── Card.module.css
│ └── Header/
│ ├── Header.jsx
│ └── Header.module.css
├── pages/
│ ├── Home/
│ │ ├── Home.jsx
│ │ └── Home.module.css
└── App.jsx

🎯 Ejemplo Práctico: Componente Card con CSS Modules

Card.module.css

Card.module.css
.card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
margin: 16px 0;
background: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.title {
margin: 0 0 12px 0;
color: #333;
font-size: 1.5rem;
font-weight: 600;
}
.description {
color: #666;
line-height: 1.6;
margin-bottom: 16px;
}
.price {
font-size: 1.25rem;
font-weight: bold;
color: #e74c3c;
margin: 0;
}
.featured {
border-color: #3498db;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.featured .title {
color: #2c3e50;
}
.buttonContainer {
margin-top: 16px;
display: flex;
gap: 8px;
}
.button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 500;
transition: background-color 0.2s ease;
}
.primary {
background-color: #3498db;
color: white;
}
.primary:hover {
background-color: #2980b9;
}
.secondary {
background-color: #95a5a6;
color: white;
}
.secondary:hover {
background-color: #7f8c8d;
}

Card.jsx

Card.jsx
import styles from './Card.module.css';
function Card({
title,
description,
price,
featured = false,
onAddToCart,
onViewDetails
}) {
// Combinar clases condicionalmente
const cardClass = featured
? `${styles.card} ${styles.featured}`
: styles.card;
return (
<div className={cardClass}>
<h3 className={styles.title}>{title}</h3>
<p className={styles.description}>{description}</p>
<p className={styles.price}>${price}</p>
<div className={styles.buttonContainer}>
<button
className={`${styles.button} ${styles.primary}`}
onClick={onAddToCart}
>
Agregar al carrito
</button>
<button
className={`${styles.button} ${styles.secondary}`}
onClick={onViewDetails}
>
Ver detalles
</button>
</div>
</div>
);
}
export default Card;

🚀 React con Vite

🤔 ¿Qué es Vite?

Vite es un bundler y herramienta de desarrollo de nueva generación creada por Evan You (creador de Vue.js). Es significativamente más rápido que herramientas tradicionales como Create React App.

Características principales:

  • Desarrollo ultra rápido: Hot Module Replacement (HMR) instantáneo
  • Configuración mínima: Funciona out-of-the-box
  • Soporte nativo: React, TypeScript, Vue, Svelte, y más
  • Build optimizado: Usa Rollup para production
  • Plugins: Ecosistema extenso de plugins

👷🏻‍♂️ Crear un proyecto React con Vite

Ventana de terminal
# Crear proyecto
pnpm create vite@latest mi-app-react
# Opciones durante la creación:
# ✔ Select a framework: › React
# ✔ Select a variant: › TypeScript + SWC
# Navegar al directorio
cd mi-app-react
# Instalar dependencias
pnpm install
# Iniciar servidor de desarrollo
pnpm dev

🌱 Estructura base de un proyecto Vite + React

  • Directoriomi-app-react/
    • Directoriopublic/
      • vite.svg
    • Directoriosrc/
      • Directorioassets/
      • Directoriocomponents/
      • Directoriohooks/
      • Directoriopages/
      • Directoriostyles/
      • Directorioutils/
      • App.tsx
      • main.tsx
      • index.css
    • package.json
    • index.html
    • vite.config.ts
    • .env