En esta página
JSX y Componentes
¿Qué es JSX?
JSX (JavaScript XML) es la extensión de sintaxis que usa React para describir la interfaz de usuario. Parece HTML dentro de JavaScript, pero es en realidad azúcar sintáctico que el compilador transforma en llamadas a funciones de React.
// Lo que escribes (JSX)
const elemento = <h1 className="titulo">¡Hola, mundo!</h1>;
// Lo que el compilador genera (JavaScript puro)
const elemento = React.createElement('h1', { className: 'titulo' }, '¡Hola, mundo!');Con TypeScript y Vite, el compilador de JSX está configurado automáticamente. No necesitas importar React en cada archivo desde React 17+, aunque es buena práctica importar el tipo React.JSX.Element para las firmas de función.
Reglas fundamentales de JSX
1. Un solo elemento raíz
Cada componente debe retornar un único elemento raíz. Si necesitas múltiples elementos, envuélvelos en un fragmento:
// ❌ Error: múltiples elementos raíz
function Mal() {
return (
<h1>Título</h1>
<p>Párrafo</p>
);
}
// ✅ Correcto: fragmento
function Bien() {
return (
<>
<h1>Título</h1>
<p>Párrafo</p>
</>
);
}2. Expresiones JavaScript entre llaves
Cualquier expresión JavaScript válida puede usarse dentro de {}. Esto incluye variables, llamadas a funciones, operadores ternarios y métodos de array:
function Info() {
const usuario = 'Ana';
const esPremium = true;
const fecha = new Date().toLocaleDateString('es-ES');
return (
<div>
<p>Usuario: {usuario.toUpperCase()}</p>
<p>Plan: {esPremium ? 'Premium' : 'Gratuito'}</p>
<p>Fecha: {fecha}</p>
<p>Suma: {2 + 2}</p>
</div>
);
}Nota: las sentencias (if, for, while) no son expresiones y no pueden ir directamente en JSX. Usa el operador ternario o lógico && en su lugar.
3. Atributos en camelCase
Los atributos HTML se escriben en camelCase en JSX, con algunas excepciones importantes:
| HTML | JSX |
|---|---|
class |
className |
for |
htmlFor |
onclick |
onClick |
tabindex |
tabIndex |
stroke-width |
strokeWidth |
<label htmlFor="email">Correo electrónico</label>
<input
id="email"
type="email"
className="campo-texto"
onChange={(e) => console.log(e.target.value)}
tabIndex={0}
/>4. El atributo style es un objeto
// ❌ String (como en HTML)
<div style="color: red; font-size: 16px">
// ✅ Objeto JavaScript
<div style={{ color: 'red', fontSize: '16px' }}>Componentes funcionales con TypeScript
Un componente React es simplemente una función que retorna JSX. Con TypeScript, tipamos sus props con interfaces:
interface PerfilUsuarioProps {
nombre: string;
avatar: string;
rol: 'admin' | 'editor' | 'lector';
articulosPublicados: number;
}
function PerfilUsuario({
nombre,
avatar,
rol,
articulosPublicados,
}: PerfilUsuarioProps): React.JSX.Element {
return (
<div className="perfil">
<img src={avatar} alt={`Avatar de ${nombre}`} />
<h2>{nombre}</h2>
<span className={`badge badge-${rol}`}>{rol}</span>
<p>{articulosPublicados} artículos publicados</p>
</div>
);
}La convención es usar PascalCase para los componentes (para distinguirlos de los elementos HTML nativos) y camelCase para las funciones y variables regulares.
Renderizado de listas
El método más común para renderizar listas es usar Array.prototype.map(). El atributo key es obligatorio y debe ser único entre los hermanos del mismo nivel:
interface Tarea {
id: string;
texto: string;
completada: boolean;
}
function ListaTareas({ tareas }: { tareas: Tarea[] }): React.JSX.Element {
return (
<ul>
{tareas.map((tarea) => (
<li
key={tarea.id}
style={{ textDecoration: tarea.completada ? 'line-through' : 'none' }}
>
{tarea.texto}
</li>
))}
</ul>
);
}¿Por qué key es tan importante?
React usa key para identificar qué elementos cambiaron, se agregaron o eliminaron. Sin ella (o con keys incorrectas como el índice del array), React puede comportarse de manera inesperada al reordenar o filtrar la lista, causando bugs difíciles de detectar como campos de formulario que no se actualizan correctamente.
Renderizado condicional
Hay varias formas de mostrar u ocultar contenido condicionalmente:
Operador ternario
function Estado({ activo }: { activo: boolean }) {
return (
<span className={activo ? 'verde' : 'rojo'}>
{activo ? 'En línea' : 'Desconectado'}
</span>
);
}Operador lógico &&
Ideal para renderizar algo o nada:
function Notificacion({ mensaje }: { mensaje: string | null }) {
return (
<div>
<h1>Dashboard</h1>
{mensaje && <div className="alerta">{mensaje}</div>}
</div>
);
}Cuidado con valores falsy: si mensaje pudiera ser 0 o '', el operador && podría renderizar 0 o nada inesperadamente. Usa comparación explícita:
{mensaje !== null && <div className="alerta">{mensaje}</div>}Retorno anticipado
Para lógica más compleja, el retorno anticipado es más legible:
function Contenido({ cargando, error, datos }: ContenidoProps) {
if (cargando) return <p>Cargando…</p>;
if (error) return <p>Error: {error}</p>;
if (!datos) return null;
return <div>{datos.titulo}</div>;
}Componentes como unidades de composición
La verdadera potencia de React está en la composición: construir componentes complejos ensamblando componentes simples.
function EncabezadoPagina(): React.JSX.Element {
return (
<header>
<Logo />
<NavegacionPrincipal />
<BotonSesion />
</header>
);
}Cada componente tiene una única responsabilidad y puede desarrollarse, probarse y reutilizarse de forma independiente. Esta es la base de la arquitectura React.
En la siguiente lección veremos cómo pasar datos entre componentes mediante props y el poderoso patrón de composición con children.
Inicia sesión para guardar tu progreso