React
JSX: sintaxis, expresiones y reglas
Explica JSX como sintaxis para describir interfaces con JavaScript, incluyendo expresiones, atributos, children, fragmentos y diferencias frente a HTML.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
React
Explica JSX como sintaxis para describir interfaces con JavaScript, incluyendo expresiones, atributos, children, fragmentos y diferencias frente a HTML.
JSX es una sintaxis para describir elementos de React dentro de JavaScript. Se parece a HTML, pero no es HTML almacenado ni llega directamente al navegador.
const element = <h1>Hola, {user.name}</h1>;Antes de ejecutarse, el tooling transforma JSX a llamadas que crean elementos de React. Con el JSX runtime moderno normalmente no necesitas importar React únicamente para escribir JSX.
Conceptualmente:
<h1 className="title">Hola</h1>se convierte en una representación equivalente a:
jsx("h1", { className: "title", children: "Hola" });El detalle exacto depende del compilador, pero la idea importante es que JSX produce objetos que describen la interfaz; no crea inmediatamente nodos del DOM.
JSX conserva muchas reglas del lenguaje JavaScript:
className y htmlFor.<label className="field" htmlFor="email">
Correo electrónico
</label>React terminará creando un atributo class y asociando el label con el input correspondiente en el DOM.
Una expresión JSX debe tener una sola raíz sintáctica:
return (
<>
<Header />
<main>Contenido</main>
</>
);El fragment <>...</> agrupa elementos sin añadir un nodo al DOM.
Cuando el fragment necesita una key, utiliza la forma explícita:
import { Fragment } from "react";
items.map((item) => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
</Fragment>
));JSX exige etiquetas cerradas:
<img src={product.imageUrl} alt={product.name} />
<input type="email" name="email" />También debes respetar el anidamiento válido del HTML resultante. React no convierte una estructura semánticamente incorrecta en una correcta.
// Incorrect HTML structure
<p>
Descripción
<div>Detalle</div>
</p>El notebook de HTML explica las reglas semánticas completas; React solo expresa esa estructura mediante JSX.
Dentro de {} puedes usar expresiones que producen un valor:
<p>Total: {unitPrice * quantity}</p>
<p>{user.isAdmin ? "Administrador" : "Cliente"}</p>No puedes colocar directamente statements como if, for o switch dentro del JSX:
// Invalid
<p>{if (isActive) "Activo"}</p>Resuelve la decisión antes del retorno o utiliza una expresión:
const statusLabel = isActive ? "Activo" : "Inactivo";
return <p>{statusLabel}</p>;React trata los hijos de forma diferente:
function Example() {
return (
<section>
<p>{"Texto"}</p>
<p>{42}</p>
<p>{null}</p>
<p>{undefined}</p>
<p>{false}</p>
</section>
);
}null, undefined y booleanos no producen contenido visible como hijos.Esta regla produce un caso importante con &&:
{count && <p>{count} resultados</p>}Cuando count es 0, React renderiza 0. Para expresar una condición booleana:
{count > 0 && <p>{count} resultados</p>}Estas dos formas son equivalentes:
<Button disabled />
<Button disabled={true} />Para false, escríbelo explícitamente o no envíes la prop:
<Button disabled={false} />Evita APIs donde muchas props booleanas puedan formar combinaciones imposibles. En esos casos una variante discriminada puede comunicar mejor el estado.
El contenido entre las etiquetas se recibe mediante la prop children:
function Card({ children }: { children: React.ReactNode }) {
return <section className="card">{children}</section>;
}
<Card>
<h2>Pedido confirmado</h2>
<p>Recibirás una notificación cuando salga a entrega.</p>
</Card>children puede contener texto, elementos, fragmentos, arrays o ausencia de contenido. No asumas que siempre es un único elemento.
JSX permite expandir un objeto:
const inputProps = {
name: "email",
type: "email",
required: true,
};
<input {...inputProps} />Es útil al reenviar props, pero puede ocultar la API y permitir atributos inesperados:
function TextField(props: React.ComponentProps<"input">) {
return <input className="text-field" {...props} />;
}El orden importa. Una prop posterior sobrescribe la anterior:
<input {...props} type="email" />Aquí type siempre será email.
La prop style recibe un objeto, no una cadena CSS:
<div style={{ display: "grid", gap: 12 }} />La primera pareja de llaves entra en JavaScript y la segunda crea el objeto. Muchas propiedades usan camelCase, como backgroundColor.
Los estilos inline son una opción puntual; React no reemplaza CSS ni obliga a una estrategia de estilos.
React escapa strings interpolados como texto:
<p>{comment.body}</p>Un valor como <script> se muestra como texto y no se interpreta automáticamente como HTML. Esto reduce un tipo común de XSS, pero no elimina todos los riesgos:
dangerouslySetInnerHTML inserta HTML real.<div dangerouslySetInnerHTML={{ __html: trustedHtml }} />El nombre es deliberadamente incómodo. Úsalo solo cuando el producto necesite renderizar HTML y el contenido haya sido sanitizado con una solución mantenida para ese contexto.
No construyas un sanitizador casero mediante reemplazos de strings.
Los archivos que contienen JSX suelen usar .tsx. TypeScript puede verificar props, elementos y eventos:
type GreetingProps = {
name: string;
unreadCount?: number;
};
function Greeting({ name, unreadCount = 0 }: GreetingProps) {
return (
<header>
<h1>Hola, {name}</h1>
{unreadCount > 0 && <p>{unreadCount} mensajes pendientes</p>}
</header>
);
}Los tipos ayudan durante desarrollo, pero desaparecen del código ejecutado. No validan automáticamente datos recibidos de una API.
JSX no corrige la semántica elegida:
<div onClick={handleSave}>Guardar</div>Aunque tenga un handler, el div no adquiere automáticamente comportamiento de botón, soporte de teclado ni semántica accesible.
<button type="button" onClick={handleSave}>
Guardar
</button>Prefiere HTML nativo y añade ARIA solo cuando la semántica necesaria no exista en un elemento nativo.
class o for en lugar de className y htmlFor.{}.count && ... sin considerar que 0 sí se renderiza.div con eventos.{} se utilizan expresiones.null, undefined y booleanos no se muestran como hijos; los números sí.{0 && <Panel />}?Fragment en lugar de <>...</>?div con onClick no equivale a un botón?0, porque el resultado de la expresión es el número cero.key.Elementos, fragments y composición básica profundiza en los valores que React combina para formar el árbol de interfaz.