Conceptos base de React, Virtual DOM, configuración con Vite y JSX.
Por qué existe React (viene de tu clase de DOM)
Hace unas semanas construiste una app manipulando el DOM a mano: querySelector, createElement, addEventListener. Y viste el reto del contador que se aceleraba — listeners que se acumulaban, estado que vivía en dos lados a la vez, y un <span> que había que acordarse de actualizar cada vez que cambiaba un dato.
Ese es exactamente el problema que React resuelve. En vanilla JS tú describes los pasos: "busca el elemento, cámbiale el texto, agrega el listener, acuérdate de quitarlo". En React describes el resultado: "cuando el contador vale N, la pantalla se ve así". React se encarga de los pasos.
Esa diferencia tiene nombre: pasar de imperativo (cómo) a declarativo (qué).
Los cuatro conceptos base
- Biblioteca de UI — React no es un framework completo: se ocupa de la interfaz. Rutas, peticiones o estilos los eliges tú (por eso en dos semanas agregamos React Router).
- Componentes — piezas de UI reutilizables. Un componente es solo una función que devuelve JSX. Nada más.
- Estado — los datos que, al cambiar, deben repintar la pantalla. React vuelve a llamar a tu función y compara.
- Virtual DOM — la razón de que esto sea rápido.
Virtual DOM, sin misticismo
Tocar el DOM real es caro: cada cambio puede disparar recálculos de layout en el navegador. Si repintaras la pantalla completa en cada cambio, la app se arrastraría.
React mantiene en memoria una representación ligera de cómo debería verse la UI. Cuando algo cambia:
- Genera la versión nueva en memoria (barato, son objetos JS).
- La compara con la anterior.
- Toca el DOM real solo donde hubo diferencias.
Por eso puedes "repintar todo" en tu cabeza y que en la práctica solo cambie un texto. Y por eso las key de las listas importan tanto: son la pista que React usa para saber quién es quién entre una versión y la siguiente.
Un componente es una función
Tres reglas que el compilador no perdona:
jsx1// ✅ Nombre con Mayúscula inicial — así React lo distingue de una etiqueta HTML 2function TarjetaProducto({ nombre, precio }) { 3 return ( // ✅ devuelve UN solo elemento raíz 4 <article className="tarjeta"> 5 <h3>{nombre}</h3> 6 <p>${precio}</p> 7 </article> 8 ); 9} 10 11// ❌ minúscula: React lo interpreta como una etiqueta HTML llamada "tarjeta" 12function tarjeta() { ... }
Si necesitas devolver varios elementos sin un contenedor extra, se usa un Fragment: <>...</>. Es un envoltorio que no genera HTML.
Setup con Vite
- Crear un proyecto rápido y liviano con
npm create vite@latest. - Vite ofrece recarga en caliente, build rápido y configuración moderna.
bash1npm create vite@latest mi-app-react -- --template react 2cd mi-app-react 3npm install 4npm run dev
JSX
JSX no es HTML: es una sintaxis que se traduce a llamadas de JavaScript. Se parece lo suficiente para ser cómodo, y difiere lo suficiente para confundir. Las diferencias que sí importan:
jsx1function Saludo() { 2 const nombre = "Juan"; 3 const activo = true; 4 5 return ( 6 <div className="saludo" style={{ color: "navy", fontSize: 18 }}> 7 <h1>Hola {nombre}</h1> 8 <p>{activo ? "En línea" : "Desconectado"}</p> 9 <label htmlFor="correo">Correo</label> 10 <input id="correo" /> 11 <img src="/logo.png" alt="Logo" /> 12 </div> 13 ); 14}
className, noclass—classes palabra reservada en JavaScript. IgualhtmlForen vez defor.{}inserta expresiones, no sentencias. Cabe una variable, una operación o un ternario; no cabe unifni unfor.stylerecibe un objeto con propiedades en camelCase y números sin unidad:{{ fontSize: 18 }}, no"font-size: 18px".- Todas las etiquetas se cierran, incluso las que en HTML no lo requerían:
<img />,<input />,<br />.
El renderizado condicional y el "0 fantasma"
Para mostrar algo condicionalmente se usa && o un ternario. Pero cuidado con este clásico:
jsx1{mensajes.length && <Aviso />} // 🚨 si length es 0, ¡pinta un "0" en pantalla! 2{mensajes.length > 0 && <Aviso />} // ✅
0 es un valor falsy pero renderizable, así que React lo pinta. Con false, null o undefined no pasa nada. Es un bug que aparece constantemente en código generado por IA — y ahora lo reconoces a simple vista.
La estructura del proyecto Vite
Después de npm run dev vas a ver esto:
mi-app-react/
├── index.html ← el único HTML; tiene <div id="root">
├── src/
│ ├── main.jsx ← punto de entrada: monta <App /> en el root
│ ├── App.jsx ← tu componente raíz — aquí empiezas
│ └── components/ ← tus componentes (créala tú)
└── package.json
El flujo es: index.html tiene un div vacío → main.jsx monta React ahí → App.jsx decide qué se ve. Toda tu app cuelga de ese árbol.
Ejemplos de Código
3 ejemplos
Punto de entrada
1import React from "react";
2import ReactDOM from "react-dom/client";
3import App from "./App.jsx";
4
5ReactDOM.createRoot(document.getElementById("root")).render(
6 <React.StrictMode>
7 <App />
8 </React.StrictMode>
9);Componente inicial
1function App() {
2 return (
3 <div className="App">
4 <h1>Hola React</h1>
5 <p>Mi primera aplicación</p>
6 </div>
7 );
8}Condicional en JSX
1function Estado({ activo }) {
2 return <span>{activo ? "Activo" : "Inactivo"}</span>;
3}Recursos
4 recursos disponibles
¡Hora de Practicar!
Práctica guiada - Setup con Vite
Práctica
Crear un proyecto con Vite y modificar el componente App con texto personalizado.
Desafío de Código
Ejercicios - JSX
Ejercicios
(1) Crear saludo dinámico, (2) listas con map, (3) render condicional con ternario.
Documentación Oficial
Reto de Lectura
Reto de Lectura — El componente que 'funciona'
Este componente React compila, renderiza y hasta parece funcionar... a veces. Rompe tres reglas de React que la IA rompe constantemente.
Este componente de lista de tareas fue generado por una IA y "funciona en la demo". Tiene 3 violaciones de las reglas de React. Encuéntralas y explica qué síntoma produce cada una (pista: dos de ellas fallan solo A VECES, que es lo peor que puede pasar).
jsx1import { useState } from "react"; 2 3function ListaTareas() { 4 const [tareas, setTareas] = useState([ 5 { texto: "Aprender React", hecha: false }, 6 { texto: "Hacer la práctica", hecha: false }, 7 ]); 8 const [nueva, setNueva] = useState(""); 9 10 function agregar() { 11 tareas.push({ texto: nueva, hecha: false }); // 🤔 12 setTareas(tareas); 13 setNueva(""); 14 } 15 16 function marcar(i) { 17 tareas[i].hecha = !tareas[i].hecha; // 🤔 18 setTareas([...tareas]); 19 } 20 21 return ( 22 <div> 23 <input value={nueva} onChange={(e) => setNueva(e.target.value)} /> 24 <button onClick={agregar}>Agregar</button> 25 <ul> 26 {tareas.map((t, index) => ( 27 <li key={index} onClick={() => marcar(index)}> 28 {t.hecha ? <s>{t.texto}</s> : t.texto} 29 </li> 30 ))} 31 </ul> 32 </div> 33 ); 34}
Preguntas:
- ¿Por qué al hacer clic en "Agregar" la lista a veces NO se actualiza en pantalla, aunque el dato sí se agregó?
marcarhace spread — ¿ya quedó bien? ¿Qué sigue estando mal y cuándo mordería (piensa en React estricto o en componentes hijos)?- ¿Qué problema causa
key={index}si agregas la función "eliminar tarea"? Describe el síntoma visual exacto. - Escribe la versión corregida de
agregarymarcar.