⚛️ 3.1 · React: el framework que cambió la web para siempre

⏱ 6h 00min ⚡ 100 XP 🏅 Mid Junior 📖 Frontend Moderno y Proyecto Final
"React no es solo una librería: es una forma de pensar la UI como funciones del estado."

🎯 Objetivo del tema

Al terminar este tema serás capaz de: Al terminar este tema serás capaz de crear aplicaciones React modernas desde cero: configurar un proyecto con Vite, escribir componentes funcionales con JSX, pasar datos con props, manejar estado local, y consumir una API pública (Rick and Morty) para mostrar datos reales. Al final tendrás tu primera SPA funcional.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

🗺️ Mapa del tema

En 2013, Jordan Walke, un ingeniero de Facebook, publicó un video interno mostrando una idea revolucionaria: tratar la UI como una FUNCIÓN del estado. Nacía React. 12 años después, es la librería frontend más usada del mundo: Netflix, Airbnb, Instagram, WhatsApp Web, Notion. Su secreto: una API mínima, un modelo mental claro (componentes = funciones), y un ecosistema enorme. Hoy empiezas tu camino en React con un ejemplo real: consumir la API pública de Rick and Morty.

1. Qué es React y por qué existe

El problema que React vino a resolver: UIs complejas con estado cambiante.

2. JSX: HTML dentro de JavaScript

La sintaxis que parece HTML pero es JavaScript. Cómo se transforma a createElement.

3. Componentes: la unidad fundamental

Funciones puras que reciben props y devuelven JSX. La base de todo.

4. Props: comunicación entre componentes

Cómo los padres pasan datos a los hijos. Unidireccional, como en HTML.

5. Estado (state): el corazón de React

Datos que cambian con el tiempo y hacen que la UI se re-renderice.

6. Proyecto real: consumir la Rick and Morty API

Tu primer fetch + useState + useEffect con datos reales de una API pública.

3.1.1 Qué es React y por qué existe

Antes de React (2011), hacer UIs interactivas era un infierno: jQuery, Backbone, Angular 1. Tenías que manipular el DOM manualmente con document.querySelector, escuchar eventos uno por uno, y rezar para que tu código funcionara cuando el estado cambiaba. Facebook tenía un problema concreto: las notificaciones de Facebook eran tan complejas que el código se volvió imposible de mantener. Crearon React para resolver ESO, no por moda.

📷 Imagen referencial: Árbol de componentes React: App contiene Header, Main, Footer. Main contiene UserList, cada UserList contiene UserCard. Props fluyen hacia abajo (padre → hijo), eventos hacia arriba.

El modelo mental de React en 1 frase

UI = f(estado). La interfaz es una FUNCIÓN del estado. Cuando el estado cambia, React re-renderiza automáticamente solo las partes que cambiaron. Es declarativo: tú describes QUÉ quieres ver (en JSX), y React se encarga del CÓMO actualizar el DOM. Es la diferencia entre pintar a mano y Photoshop: el resultado es el mismo, pero la productividad es 10x.

AspectojQuery / Vanilla JS (2010)React (2013+)
ParadigmaImperativo: tú manipulas el DOM.Declarativo: describes el resultado, React lo actualiza.
EstadoLo guardas en variables globales o atributos.Lo guardas en useState; React lo sincroniza con la UI.
Re-renderTú lo programas: removeChild, appendChild.Automático: React detecta el cambio y re-renderiza.
ComposiciónFunciones que devuelven HTML strings.Componentes: funciones que devuelven JSX.
Curva de aprendizajeBaja al inicio, alta al crecer.Más empinada al inicio, baja al crecer.
⭐ React = librería, no framework: React no es un framework completo: es una LIBRERÍA de UI. No tiene routing, ni estado global, ni HTTP. Tú eliges: React Router para navegación, Axios para HTTP, Redux/Zustand para estado global. Esta 'modularidad' es la razón por la que el ecosistema de React es ENORME: hay solución para cada problema, y tú montas la tuya.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

3.1.2 JSX: HTML dentro de JavaScript

JSX (JavaScript XML) es la sintaxis que usa React: parece HTML, pero es JavaScript. Es el 'lenguaje' de React. Cuando escribes <h1>Hola</h1> en un archivo .jsx, no es HTML literal: se transforma en React.createElement('h1', null, 'Hola') antes de ejecutarse. Esa transformación la hace Vite (o Webpack) automáticamente. Es el paso de la magia: tú escribes algo que parece HTML, pero es JavaScript de verdad.

📷 Imagen referencial: Transformación JSX → JavaScript: el código JSX que escribes se convierte en llamadas a React.createElement. La sintaxis es más legible y el bundle final ejecuta el JS.

Las 8 reglas de oro de JSX

  • 1. SIEMPRE devuelve UN solo elemento raíz (envuelve en <div> o <> si necesitas varios).
  • 2. class se escribe className (porque 'class' es palabra reservada en JS).
  • 3. Los eventos van en camelCase: onClick, onChange, onSubmit (no onclick).
  • 4. Los atributos booleanos se escriben solos: <input disabled />, no <input disabled='true' />.
  • 5. style recibe un objeto: style={{ color: 'red', fontSize: '16px' }} (camelCase + comillas).
  • 6. Las expresiones JS van entre {}: <h1>{nombre}</h1>, <p>{2 + 2}</p>.
  • 7. Las condicionales se hacen con ternario o &&: {activo ? 'Sí' : 'No'}, {lista.length > 0 && <Lista />}.
  • 8. Los comentarios son /* */ (no // dentro de JSX, que es multilínea).
// JSX que escribes (lo que ves en el código):
function Saludo({ nombre, edad }) {
  return (
    <div className="tarjeta">
      <h1>Hola, {nombre}!</h1>
      <p>Tienes {edad} años.</p>
      {edad >= 18 && <p>Eres mayor de edad.</p>}
      <button onClick={handleClick} style={{ background: 'blue' }}>
        Click aquí
      </button>
    </div>
  );
}

// JavaScript al que se transforma (lo que se ejecuta):
function Saludo({ nombre, edad }) {
  return React.createElement(
    'div',
    { className: 'tarjeta' },
    React.createElement('h1', null, 'Hola, ', nombre, '!'),
    React.createElement('p', null, 'Tienes ', edad, ' años.'),
    edad >= 18 && React.createElement('p', null, 'Eres mayor de edad.'),
    React.createElement(
      'button',
      { onClick: handleClick, style: { background: 'blue' } },
      'Click aquí'
    )
  );
}

// El navegador ejecuta la versión createElement. Tú escribes la versión JSX.
// Es solo azúcar sintáctico: el resultado es idéntico.

JSX vs JavaScript: la misma cosa, syntaxis diferente

⭐ JSX NO es HTML: JSX NO es HTML. Es JavaScript disfrazado. Por eso class es className, onclick es onClick, y los comentarios son {/* */}. Si olvidas esta distinción, tus componentes rompen en producción y no entiendes por qué ('yo escribí HTML y no funciona'). Tómate 5 minutos en grabar las 8 reglas: te ahorra horas de debugging.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

3.1.3 Componentes: la unidad fundamental de React

En React, TODO es un componente. Una página es un componente. Un botón es un componente. Un input es un componente. Un componente es una FUNCIÓN que recibe props (datos) y devuelve JSX (lo que se ve en pantalla). Es la misma idea que las funciones de JavaScript, pero devuelven UI en vez de números. Si entiendes esto, entiendes React.

Anatomía de un componente funcional

// 1. El componente más simple del mundo
function Saludo() {
  return <h1>Hola mundo</h1>;
}

// 2. Con props (datos que vienen del padre)
function Saludo({ nombre, edad }) {
  return (
    <div>
      <h1>Hola, {nombre}!</h1>
      <p>Tienes {edad} años.</p>
    </div>
  );
}

// 3. Con arrow function (más conciso, mismo resultado)
const Saludo = ({ nombre, edad }) => (
  <div>
    <h1>Hola, {nombre}!</h1>
    <p>Tienes {edad} años.</p>
  </div>
);

// 4. Con desestructuración con valores por defecto
const Saludo = ({ nombre = 'Anónimo', edad = 0 }) => (
  <div>
    <h1>Hola, {nombre}!</h1>
    <p>Tienes {edad} años.</p>
  </div>
);

// Uso (en el componente padre):
<Saludo nombre="Ana" edad={25} />
<Saludo nombre="Luis" />  // edad = 0 por defecto

4 formas de escribir el mismo componente

⭐ Un componente = una responsabilidad: Los componentes en React son como las funciones en JavaScript: deben hacer UNA cosa y hacerla bien. Si tu componente tiene más de 200 líneas, probablemente está haciendo demasiado. Divídelo en sub-componentes. La regla: si puedes nombrar una parte de la UI ('este es el header', 'esta es la lista', 'este es el botón'), es un componente. Es la diferencia entre un código mantenible y un monolito de 1000 líneas.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

3.1.4 Props: comunicación entre componentes

Los props son la forma en que los componentes PADRE pasan datos a los componentes HIJO. Es UNIDIRECCIONAL: los datos fluyen de arriba hacia abajo, como el agua. El padre decide qué pasa; el hijo solo recibe y muestra. Si el hijo necesita enviar algo al padre, usa callbacks (funciones pasadas como props) o eventos. Es el mismo principio que HTML: <img src='...' /> el src es un prop que el padre le pasa al img.

Ejemplo completo: lista de personajes

// El componente HIJO: solo recibe props y muestra
function CharacterCard({ character, onSelect }) {
  return (
    <div className="character-card" onClick={() => onSelect(character.id)}>
      <img src={character.image} alt={character.name} />
      <h3>{character.name}</h3>
      <p>{character.species} - {character.status}</p>
    </div>
  );
}

// El componente PADRE: decide QUÉ pasa, renderiza la lista
function CharacterList() {
  const characters = [...];  // array de personajes de la API

  // Función que se pasa como prop: el hijo la llama, el padre maneja la lógica
  const handleSelect = (id) => {
    console.log('Seleccionaste:', id);
    // Aquí irías a la página de detalle, etc.
  };

  return (
    <div className="character-list">
      {characters.map(char => (
        <CharacterCard
          key={char.id}  // SIEMPRE key único en listas
          character={char}
          onSelect={handleSelect}
        />
      ))}
    </div>
  );
}

// Reglas de los props:
// 1. Los props son INMUTABLES: el hijo NO puede modificarlos.
// 2. SIEMPRE key único al renderizar listas (key={char.id}).
// 3. Los props pueden ser cualquier cosa: strings, números, objetos, funciones, JSX.
// 4. props.children es el contenido que se pasa entre las etiquetas: <Saludo>Hola</Saludo> → props.children = 'Hola'.

Props: comunicación unidireccional padre → hijo

⭐ key={id}, nunca key={index}: Si olvidas el key al renderizar una lista, ves el warning 'Each child in a list should have a unique key prop' en consola. React lo necesita para saber QUÉ elemento cambió cuando actualizas la lista. Es como un DNI: identifica cada elemento de forma única. Usa SIEMPRE un ID estable (id de la BD), NUNCA el índice del array. Si usas el índice, React confunde los elementos cuando reordenas la lista.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

3.1.5 Estado (state): el corazón de React

El estado son los datos que CAMBIAN con el tiempo y hacen que la UI se re-renderice. Es la diferencia entre una página HTML estática y una app interactiva. En React, el estado se maneja con el hook useState. Cuando llamas a setState, React re-renderiza el componente automáticamente. Es el motor de la interactividad.

useState: el hook más usado de React

import { useState } from 'react';

function Contador() {
  // const [valor, setValor] = useState(valorInicial);
  const [count, setCount] = useState(0);
  const [nombre, setNombre] = useState('');
  const [usuario, setUsuario] = useState(null);
  const [lista, setLista] = useState([]);
  const [cargando, setCargando] = useState(false);

  return (
    <div>
      <p>Contador: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
      <button onClick={() => setCount(0)}>Reset</button>

      <input
        value={nombre}
        onChange={(e) => setNombre(e.target.value)}
        placeholder="Tu nombre"
      />
      <p>Hola, {nombre || 'anónimo'}</p>
    </div>
  );
}

// Las 3 reglas del useState:
// 1. NUNCA mutes el estado directamente: setCount(count + 1), NO count++.
// 2. Usa SIEMPRE el setter que devuelve useState: setCount, setNombre, etc.
// 3. Si el nuevo estado depende del anterior, usa la forma funcional:
//    setCount(prev => prev + 1)  // más seguro que setCount(count + 1)

useState: el hook fundamental

⭐ NUNCA mutes el estado directamente: NUNCA mutes el estado directamente. count++ NO funciona en React. SIEMPRE setCount(count + 1) o setCount(prev => prev + 1). Es la regla #1 de React. Si no la cumples, React no se entera del cambio y la UI no se actualiza. Es el error #1 de los principiantes: 'modifiqué la variable pero la UI no cambió'. La respuesta: NO se modifica la variable, se llama al setter. Es como una caja fuerte: no tocas el contenido, abres la puerta con la combinación.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

3.1.6 Proyecto real: consumir la Rick and Morty API

Es hora de hacer algo REAL. Vamos a construir tu primer componente completo con datos de una API pública: la Rick and Morty API (https://rickandmortyapi.com/), que es GRATIS, sin autenticación, y devuelve personajes, episodios, ubicaciones de la serie. Vas a ver cómo se conectan los conceptos: useState para guardar los datos, useEffect para hacer el fetch cuando el componente se monta, JSX para renderizar, props para pasar cada personaje al componente hijo.

API pública: Rick and Morty (gratis, sin auth)

  • Endpoint: https://rickandmortyapi.com/api/character
  • Sin autenticación ni API key: solo haz fetch.
  • Devuelve: array de personajes con name, status, species, gender, image, location, etc.
  • Paginada: usa ?page=2, ?page=3, etc.
  • Búsqueda: ?name=Rick, ?status=alive, ?species=human.
  • Documentación: https://rickandmortyapi.com/documentation

Tu primer componente real: CharacterList completo

import { useState, useEffect } from 'react';

// Componente hijo: recibe UN personaje y lo muestra
function CharacterCard({ character }) {
  return (
    <div className="character-card">
      <img src={character.image} alt={character.name} />
      <h3>{character.name}</h3>
      <p><strong>Especie:</strong> {character.species}</p>
      <p><strong>Estado:</strong> {character.status}</p>
      <p><strong>Origen:</strong> {character.origin.name}</p>
    </div>
  );
}

// Componente padre: hace el fetch, maneja loading y error
function CharacterList() {
  // useState: 3 estados para 3 cosas distintas
  const [characters, setCharacters] = useState([]);
  const [cargando, setCargando] = useState(true);
  const [error, errorMensaje] = useState(null);

  // useEffect: se ejecuta UNA vez al montar el componente
  useEffect(() => {
    // Función async para hacer el fetch
    async function fetchCharacters() {
      try {
        const response = await fetch('https://rickandmortyapi.com/api/character');
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const data = await response.json();
        setCharacters(data.results);  // .results es donde está el array
      } catch (err) {
        errorMensaje(err.message);
      } finally {
        setCargando(false);
      }
    }
    fetchCharacters();
  }, []);  // [] = solo al montar. Sin esto, sería un loop infinito.

  // Renderizado condicional: 3 estados posibles
  if (cargando) return <p className="loading">Cargando personajes...</p>;
  if (error) return <p className="error">Error: {error}</p>;

  return (
    <div className="character-grid">
      {characters.map(char => (
        <CharacterCard key={char.id} character={char} />
      ))}
    </div>
  );
}

// Uso en App.jsx
function App() {
  return (
    <div className="app">
      <h1>Rick and Morty — Personajes</h1>
      <CharacterList />
    </div>
  );
}

Tu primer componente con datos reales de una API pública

⭐ Rick and Morty: el 'Hola Mundo' de las APIs: La Rick and Morty API es perfecta para aprender porque es 100% gratis, sin API key, sin rate limits agresivos, y devuelve datos JSON limpios. Otras APIs similares que puedes probar después: REST Countries (https://restcountries.com/) para datos de países, JSONPlaceholder (https://jsonplaceholder.typicode.com/) para datos fake de prueba, OpenWeatherMap (necesita API key gratis) para clima, PokeAPI (https://pokeapi.co/) para Pokémon. Todas con la misma estructura: fetch + useState + useEffect. Una vez que aprendes el patrón con una, las entiendes todas.
🎬
Video del instructor

El administrador aún no ha insertado un video para esta sección.

📚 Contenido ampliado

Material adicional, referencias externas verificadas y ejemplos extendidos.

🤖 AI Mission

La mejor forma de aprender React es hacer un fetch real a una API pública.

Misión: Crea tu primer proyecto React con Vite, configura la estructura de carpetas, y construye un componente que consuma la Rick and Morty API para mostrar 20 personajes con su imagen, nombre, especie, y estado. Agrega un campo de búsqueda que filtre en vivo (sin recargar la página). Pídele a la IA que revise tu código. Anota en tu cuaderno: ¿qué fue lo más difícil de entender: JSX, props, state, o el fetch con useEffect?

Pasos sugeridos

  1. Instala Vite: npm create vite@latest mi-rick-morty -- --template react.
  2. Entra a la carpeta, npm install, npm run dev. Abre localhost:5173.
  3. Crea components/CharacterCard.jsx con el componente hijo que recibe props.
  4. Crea components/CharacterList.jsx con useState, useEffect, fetch a la API.
  5. Crea App.jsx que renderice CharacterList dentro de un layout.
  6. Estiliza con CSS modules o un archivo App.css: grid de tarjetas, hover, imagen circular.
  7. Agrega un campo de búsqueda: <input> controlado con useState. Filtra con .filter() en tiempo real.
  8. Maneja los 3 estados: cargando (spinner), error (mensaje), éxito (grid de personajes).
  9. Prueba: busca 'Rick', 'Morty', 'Summer', 'Bird'. ¿Filtra en vivo?
  10. Pídele a la IA: 'Tengo esta app de Rick and Morty en React. Sugiere 2 mejoras: performance (useMemo, useCallback), features (paginación, filtro por status). NO me des código, dime QUÉ agregar.'
  11. Aplica 2 mejoras. Vuelve a probar.
  12. Anota en tu cuaderno, bajo 'Mi primer fetch real': qué entendiste y qué te costó.

📓 Entregable: Capturas de: la app funcionando, búsqueda en vivo filtrando personajes, código de los 3 componentes, y media página de cuaderno con tu reflexión.

🚫 Errores típicos de razonamiento

Error 1: Mutar el estado directamente (count++ en vez de setCount(count+1)).
Por qué: En React, el estado es INMUTABLE. Si haces count++ o lista.push(item), React NO se entera del cambio y la UI no se actualiza. SIEMPRE usa el setter: setCount(count+1) o setCount(prev => prev+1). Es la regla #1 de React. Si tu UI no se actualiza, este es el primer lugar donde mirar.
Error 2: Olvidar el array de dependencias en useEffect.
Por qué: Si escribes useEffect(() => { fetch(...) }, ) SIN el array de dependencias, el efecto se ejecuta EN CADA render, causando un loop infinito de fetches. Regla: useEffect(fn, []) se ejecuta SOLO al montar. useEffect(fn, [dep]) se ejecuta cuando dep cambia. useEffect(fn) sin array = cada render = loop. Es uno de los errores más comunes y difíciles de debuggear.
Error 3: Usar index como key en listas: key={index}.
Por qué: Si usas el índice del array como key, React confunde los elementos cuando reordenas o filtras la lista. Ejemplo: si borras el primer elemento, React cree que todos los demás cambiaron y re-renderiza TODO. Usa SIEMPRE un ID estable: key={character.id}. Es la diferencia entre 1ms de re-render y 100ms.
Error 4: No manejar el estado de loading y error en fetches.
Por qué: Si solo muestras los datos cuando llegan, el usuario ve una pantalla en blanco durante 1-2 segundos. Peor: si la API falla, ve una página rota sin saber qué pasó. SIEMPRE maneja los 3 estados: cargando (spinner), error (mensaje claro), éxito (datos). Es el patrón fundamental de cualquier app que consume APIs. Los juniors lo olvidan; los seniors lo aplican siempre.
Error 5: Devolver varios elementos sin un contenedor padre en JSX.
Por qué: En JSX, un componente debe devolver UN solo elemento raíz. Si escribes return <h1>Hola</h1><p>Mundo</p>, React lanza un error de sintaxis ('JSX expressions must have one parent element'). Solución: envuelve en un <div>, o usa un Fragment: <>...</> (sin nombre, sin DOM extra). Es la regla #1 de JSX.

🧪 Laboratorio práctico

El primer fetch real es el rito de paso de todo frontend developer.

Laboratorio: Tu primera SPA con React + Rick and Morty API + búsqueda en vivo

Objetivo: Crear una Single Page Application con React + Vite que consuma la Rick and Morty API, muestre los personajes en un grid, y tenga búsqueda en vivo (filtra sin recargar). Practicarás: setup con Vite, componentes funcionales, JSX, props, useState, useEffect, fetch, manejo de loading/error, y CSS Grid.

Pasos

  1. Crea el proyecto: npm create vite@latest mi-rick-morty -- --template react.
  2. cd mi-rick-morty, npm install, npm run dev. Abre localhost:5173.
  3. Borra el contenido de src/ que viene por defecto (App.css, index.css, etc.).
  4. Crea components/CharacterCard.jsx: recibe { character }, muestra imagen + nombre + especie + estado + origen.
  5. Crea components/CharacterList.jsx: useState para characters, cargando, error, searchTerm. useEffect para fetch al montar.
  6. Crea components/SearchBar.jsx: input controlado que actualiza el searchTerm en el padre (lift state up).
  7. App.jsx: layout principal con título y los componentes.
  8. Filtra con .filter(char => char.name.toLowerCase().includes(searchTerm.toLowerCase())).
  9. Estiliza con App.css: CSS Grid responsive, tarjetas con border-radius, hover, imagen circular.
  10. Agrega estados: si cargando, spinner. Si error, mensaje rojo. Si vacío, 'No se encontraron personajes'.
  11. Prueba: busca 'Rick' (debe filtrar), 'Bird' (debe mostrar personajes-pájaro), 'XYZ' (debe mostrar mensaje vacío).
  12. Haz commit: 'feat: SPA de Rick and Morty con React + Vite + búsqueda en vivo'.
  13. Sube a Vercel o Netlify. Comparte la URL.

📓 Entregable: URL pública de tu app en Vercel/Netlify, capturas de: personajes cargados, búsqueda filtrando en vivo, mensaje de sin resultados, código de los 3 componentes, y commit en Git.

📓 Tu cuaderno: Anota pseudocódigo, diagramas, errores que encontraste y respuestas a "explica sin código". La escritura manual refuerza tu razonamiento. Tu profesor puede pedirte que subas fotos de páginas específicas.