JSX en React: declarar interfaces con expresividad y reglas claras

Capítulo 2

Tiempo estimado de lectura: 9 minutos

+ Ejercicio

Qué es JSX y por qué se usa

JSX es una sintaxis declarativa que te permite describir la interfaz (UI) usando una forma muy parecida a HTML, pero dentro de JavaScript. No es HTML real: es una extensión de sintaxis que, al compilarse, se convierte en llamadas a funciones de React que crean elementos. La idea práctica es que escribes “cómo debería verse” la UI en función de datos y estado, y React se encarga de actualizar lo necesario.

Dos ideas clave para trabajar con JSX con seguridad: (1) dentro de JSX puedes incrustar expresiones de JavaScript usando llaves {}; (2) los “atributos” que ves en JSX a veces se parecen a HTML, pero siguen reglas de JavaScript y del API de React.

JSX y JavaScript: expresiones e interpolación

Expresiones dentro de llaves

Dentro de {} puedes poner cualquier expresión (algo que produce un valor): variables, ternarios, llamadas a funciones, map, etc. No puedes poner sentencias como if, for o switch directamente (porque no son expresiones). Para esas situaciones, usa ternarios, operadores lógicos o calcula el valor antes del return.

function Welcome({ user }) {  const fullName = user.firstName + " " + user.lastName;  return (    <h2>Hola, {fullName}!</h2>  );}

Condicionales comunes

function Status({ isOnline }) {  return (    <p>      Estado: {isOnline ? "Conectado" : "Desconectado"}    </p>  );}
function Notifications({ count }) {  return (    <div>      <h3>Bandeja</h3>      {count > 0 && <p>Tienes {count} nuevas</p>}    </div>  );}

Listas con map

Una lista en UI suele venir de un array. En JSX, lo típico es transformar el array en elementos con map. Recuerda que cada elemento de una lista debe tener una key estable.

function TodoList({ todos }) {  return (    <ul>      {todos.map((t) => (        <li key={t.id}>{t.title}</li>      ))}    </ul>  );}

Atributos en JSX: diferencias con HTML y reglas frecuentes

Un solo elemento raíz

Un componente debe devolver un único “nodo raíz”. Si necesitas varios hermanos, envuélvelos en un contenedor o usa un fragmento.

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

// ❌ Incorrecto: dos elementos raízreturn (  <h2>Título</h2>  <p>Texto</p>);
// ✅ Opción 1: contenedorreturn (  <div>    <h2>Título</h2>    <p>Texto</p>  </div>);
// ✅ Opción 2: fragmentoreturn (  <>    <h2>Título</h2>    <p>Texto</p>  </>);

camelCase en propiedades y eventos

En JSX, muchas propiedades siguen la convención de JavaScript: camelCase. Esto se nota especialmente en eventos y en algunas propiedades del DOM.

  • Eventos: onClick, onChange, onSubmit (no onclick).
  • Propiedades: tabIndex, readOnly, maxLength.
function Button() {  function handleClick() {    console.log("click");  }  return (    <button type="button" onClick={handleClick}>      Guardar    </button>  );}

class vs className

En JSX no se usa class (palabra reservada en JavaScript). Se usa className.

function Card() {  return (    <section className="card">      <h3 className="card__title">Producto</h3>    </section>  );}

Estilos inline: objeto en lugar de string

El atributo style recibe un objeto JavaScript, no una cadena. Las propiedades CSS se escriben en camelCase (por ejemplo, backgroundColor).

function Price({ value }) {  const isHigh = value > 100;  return (    <p      style={{        color: isHigh ? "crimson" : "seagreen",        fontWeight: 600,        marginTop: 8,      }}    >      ${value}    </p>  );}

Atributos booleanos

Si un atributo booleano es true, puedes escribirlo sin valor. Si depende de una expresión, usa llaves.

function Form({ isDisabled }) {  return (    <input      type="text"      disabled={isDisabled}      readOnly    />  );}

HTML vs props: misma forma, distinto significado

En JSX puedes usar etiquetas HTML (como <div>, <input>) y también componentes (como <UserCard />). La diferencia práctica: en etiquetas HTML, los atributos se traducen a propiedades del DOM; en componentes, esos “atributos” se convierten en props que tú defines.

function UserCard({ name, isPro }) {  return (    <article className={isPro ? "pro" : "basic"}>      <h3>{name}</h3>    </article>  );}function App() {  return (    <div>      {/* name e isPro son props para UserCard */}      <UserCard name="Ana" isPro={true} />      {/* className es una prop del DOM para un div */}      <div className="separator" />    </div>  );}

Guía práctica: convertir una UI deseada a JSX

Una forma efectiva de aprender JSX es partir de una UI “en palabras” o un boceto y convertirlo a estructura y expresiones.

Paso a paso (método recomendado)

  • 1) Identifica el contenedor raíz que agrupa todo lo que vas a devolver.
  • 2) Escribe la estructura estática (etiquetas y jerarquía) sin datos dinámicos.
  • 3) Marca qué partes son dinámicas (texto, clases, estilos, atributos, listas).
  • 4) Sustituye esas partes por expresiones con {} (variables, ternarios, map).
  • 5) Revisa reglas: className, style como objeto, camelCase, key en listas.

Ejemplo 1: “Tarjeta de perfil”

UI deseada: una tarjeta con avatar, nombre, y un badge “PRO” si el usuario es premium. Si no hay avatar, mostrar un círculo con iniciales.

1) Estructura base:

function ProfileCard() {  return (    <article>      <div></div>      <div>        <h3></h3>      </div>    </article>  );}

2) Dinamismo con expresiones:

function ProfileCard({ user }) {  const initials = (user.name || "?")    .split(" ")    .slice(0, 2)    .map((p) => p[0]?.toUpperCase())    .join("");  return (    <article className="profile">      <div className="profile__avatar">        {user.avatarUrl ? (          <img src={user.avatarUrl} alt={user.name} />        ) : (          <span aria-label="Iniciales">{initials}</span>        )}      </div>      <div className="profile__info">        <h3>{user.name}</h3>        {user.isPro && <span className="badge">PRO</span>}      </div>    </article>  );}

Ejemplo 2: “Tabla de productos con estado visual”

UI deseada: tabla con nombre, stock y una marca visual en rojo si el stock es 0. Mostrar “Sin productos” si la lista está vacía.

function ProductTable({ products }) {  if (products.length === 0) {    return <p>Sin productos</p>;  }  return (    <table>      <thead>        <tr>          <th>Nombre</th>          <th>Stock</th>        </tr>      </thead>      <tbody>        {products.map((p) => (          <tr key={p.id}>            <td>{p.name}</td>            <td              style={{                color: p.stock === 0 ? "crimson" : "inherit",                fontWeight: p.stock === 0 ? 700 : 400,              }}            >              {p.stock === 0 ? "Agotado" : p.stock}            </td>          </tr>        ))}      </tbody>    </table>  );}

Ejemplo 3: “Formulario controlado visualmente (atributos y eventos)”

UI deseada: input de email, botón deshabilitado si el email está vacío, y un mensaje de error si no contiene @.

function EmailForm() {  const [email, setEmail] = React.useState("");  const isEmpty = email.trim() === "";  const isInvalid = !isEmpty && !email.includes("@");  function handleSubmit(e) {    e.preventDefault();    alert("Enviado: " + email);  }  return (    <form onSubmit={handleSubmit}>      <label>        Email        <input          type="email"          value={email}          onChange={(e) => setEmail(e.target.value)}          aria-invalid={isInvalid}        />      </label>      {isInvalid && (        <p style={{ color: "crimson" }}>Debe incluir @</p>      )}      <button type="submit" disabled={isEmpty}>        Enviar      </button>    </form>  );}

Fragmentos: agrupar sin añadir nodos al DOM

Los fragmentos te permiten devolver varios elementos sin envolverlos en un <div>. Úsalos cuando el contenedor extra afecte estilos, layout o semántica.

function ListWithSeparator({ items }) {  return (    <ul>      {items.map((item, idx) => (        <React.Fragment key={item.id}>          <li>{item.label}</li>          {idx < items.length - 1 && <hr />}        </React.Fragment>      ))}    </ul>  );}

Nota: si necesitas key en un fragmento dentro de un map, usa <React.Fragment key=...> (la forma corta <></> no acepta atributos).

Errores típicos en JSX: diagnóstico y corrección

ProblemaSíntoma / errorCausaCorrección
Llaves mal ubicadas en atributosUnexpected token o el valor no se aplicaMezclar comillas y llaves incorrectamenteSi es string literal: comillas. Si es expresión: llaves.
Usar class en lugar de classNameWarning o estilos no aplican como esperasclass no es el atributo correcto en JSXUsa className.
Style como stringWarning o estilos ignoradosstyle espera un objetoUsa style={{ color: "red" }}.
Renderizar objetos directamenteObjects are not valid as a React childIntentas imprimir un objeto en JSXRenderiza una propiedad, conviértelo a string o mapea a elementos.
Olvidar el elemento raízAdjacent JSX elements must be wrappedDevuelves hermanos sin wrapperEnvuelve en <div> o fragmento.

1) Llaves y comillas: patrones correctos

Regla práctica: comillas para literales string; llaves para expresiones.

// ✅ String literal<input placeholder="Tu nombre" />// ✅ Expresión (variable)<input placeholder={placeholderText} />// ✅ Expresión (template string)<input placeholder={`${first} ${last}`} />// ❌ Incorrecto: llaves dentro de comillas<input placeholder="{placeholderText}" />

2) Renderizar objetos: cómo detectarlo y arreglarlo

Si ves Objects are not valid as a React child, revisa qué estás poniendo entre llaves. Ejemplo típico:

function Debug({ user }) {  return <p>Usuario: {user}</p>; // ❌ user es un objeto}

Correcciones comunes:

// ✅ Renderizar una propiedadreturn <p>Usuario: {user.name}</p>;// ✅ Convertir a string (para depuración)return <pre>{JSON.stringify(user, null, 2)}</pre>;

3) Confundir sentencias con expresiones

Esto falla porque if no es una expresión dentro de JSX:

function Example({ ok }) {  return (    <div>      {if (ok) { <p>OK</p> }}    </div>  );}

Alternativas correctas:

function Example({ ok }) {  return (    <div>      {ok ? <p>OK</p> : <p>No OK</p>}    </div>  );}
function Example({ ok }) {  return (    <div>      {ok && <p>OK</p>}    </div>  );}

4) Atributos del DOM vs props: confusiones frecuentes

  • En DOM: onClick espera una función. Si escribes onClick={handleClick()}, ejecutas la función al renderizar (casi siempre es un bug).
  • En componentes: puedes pasar cualquier tipo de dato como prop (string, número, boolean, objeto, función), pero recuerda que al renderizar debes convertirlo a algo renderizable (texto o elementos).
function App() {  function handleClick() {    console.log("clicked");  }  return (    <>      {/* ✅ pasar la función */}      <button onClick={handleClick}>Click</button>      {/* ❌ se ejecuta al renderizar */}      {/* <button onClick={handleClick()}>Click</button> */}    </>  );}

Ahora responde el ejercicio sobre el contenido:

¿Cuál opción describe correctamente cómo manejar condicionales dentro de JSX?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

En JSX, las llaves {} aceptan expresiones (que producen un valor). Por eso, para condicionales se usan ternarios u operadores lógicos, o se prepara el resultado antes del return, en lugar de sentencias como if.

Siguiente capítulo

Props en React: entradas, contratos y flujo de datos unidireccional

Arrow Right Icon
Portada de libro electrónico gratuitaReact para principiantes: mentalidad de componentes y manejo de estado
17%

React para principiantes: mentalidad de componentes y manejo de estado

Nuevo curso

12 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.