🎯 Objetivo del tema
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.
El problema que React vino a resolver: UIs complejas con estado cambiante.
La sintaxis que parece HTML pero es JavaScript. Cómo se transforma a createElement.
Funciones puras que reciben props y devuelven JSX. La base de todo.
Cómo los padres pasan datos a los hijos. Unidireccional, como en HTML.
Datos que cambian con el tiempo y hacen que la UI se re-renderice.
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.
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.
| Aspecto | jQuery / Vanilla JS (2010) | React (2013+) |
|---|---|---|
| Paradigma | Imperativo: tú manipulas el DOM. | Declarativo: describes el resultado, React lo actualiza. |
| Estado | Lo guardas en variables globales o atributos. | Lo guardas en useState; React lo sincroniza con la UI. |
| Re-render | Tú lo programas: removeChild, appendChild. | Automático: React detecta el cambio y re-renderiza. |
| Composición | Funciones que devuelven HTML strings. | Componentes: funciones que devuelven JSX. |
| Curva de aprendizaje | Baja al inicio, alta al crecer. | Más empinada al inicio, baja al crecer. |
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.
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
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 defecto4 formas de escribir el mismo componente
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
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
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
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
- Instala Vite: npm create vite@latest mi-rick-morty -- --template react.
- Entra a la carpeta, npm install, npm run dev. Abre localhost:5173.
- Crea components/CharacterCard.jsx con el componente hijo que recibe props.
- Crea components/CharacterList.jsx con useState, useEffect, fetch a la API.
- Crea App.jsx que renderice CharacterList dentro de un layout.
- Estiliza con CSS modules o un archivo App.css: grid de tarjetas, hover, imagen circular.
- Agrega un campo de búsqueda: <input> controlado con useState. Filtra con .filter() en tiempo real.
- Maneja los 3 estados: cargando (spinner), error (mensaje), éxito (grid de personajes).
- Prueba: busca 'Rick', 'Morty', 'Summer', 'Bird'. ¿Filtra en vivo?
- 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.'
- Aplica 2 mejoras. Vuelve a probar.
- 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
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.
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.
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.
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.
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
- Crea el proyecto: npm create vite@latest mi-rick-morty -- --template react.
- cd mi-rick-morty, npm install, npm run dev. Abre localhost:5173.
- Borra el contenido de src/ que viene por defecto (App.css, index.css, etc.).
- Crea components/CharacterCard.jsx: recibe { character }, muestra imagen + nombre + especie + estado + origen.
- Crea components/CharacterList.jsx: useState para characters, cargando, error, searchTerm. useEffect para fetch al montar.
- Crea components/SearchBar.jsx: input controlado que actualiza el searchTerm en el padre (lift state up).
- App.jsx: layout principal con título y los componentes.
- Filtra con .filter(char => char.name.toLowerCase().includes(searchTerm.toLowerCase())).
- Estiliza con App.css: CSS Grid responsive, tarjetas con border-radius, hover, imagen circular.
- Agrega estados: si cargando, spinner. Si error, mensaje rojo. Si vacío, 'No se encontraron personajes'.
- Prueba: busca 'Rick' (debe filtrar), 'Bird' (debe mostrar personajes-pájaro), 'XYZ' (debe mostrar mensaje vacío).
- Haz commit: 'feat: SPA de Rick and Morty con React + Vite + búsqueda en vivo'.
- 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.