Clase 29 - React - Introducción
🚀 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.
<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.
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 propsfunction 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 propsfunction 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:
- Divide y vencerás: Secciona tu interfaz en partes reutilizables.
- Responsabilidad única: Cada componente debe tener una sola responsabilidad.
- Nombres descriptivos: Usa nombres que describan claramente qué hace el componente.
- Reutilización: Diseña componentes que puedan usarse en diferentes contextos.
// ❌ Componente que hace demasiadas cosasfunction 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>© 2025 Mi Sitio Web</p> </footer> </div> );}
// ✅ Componentes bien estructuradosfunction 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>© 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 { 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
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
# Crear proyectopnpm create vite@latest mi-app-react
# Opciones durante la creación:# ✔ Select a framework: › React# ✔ Select a variant: › TypeScript + SWC
# Navegar al directoriocd mi-app-react
# Instalar dependenciaspnpm install
# Iniciar servidor de desarrollopnpm 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