Cuando trabajamos con React y necesitamos escribir el HTML de un fichero o componente, no vamos a escribir HTML directamente (aunque pueda parecer que lo estamos haciendo). En React se utiliza una sintaxis llamada JSX, que realmente es código Javascript con apariencia de HTML que se escribe en el interior de funciones llamados componentes funcionales en los que profundizaremos un poco más adelante.
¿Qué es JSX?
Como hemos mencionado, JSX es código Javascript con apariencia de marcado HTML. Observa la siguiente función de ejemplo que devuelve un fragmento de código JSX:
function component() {
return <h1>Hola</h1>;
}
Si conoces minimamente Javascript, esto te resultará bastante extraño, ya que no se puede añadir una etiqueta HTML directamente en el código Javascript (observa que no tiene las comillas de un string). Pero como hemos mencionado, estamos trabajando con ficheros .jsx
que son procesados por Vite y React antes de llegar al navegador, por lo que el Javascript final es diferente.
Para dejarlo más claro, vamos a ver que es realmente lo que le llega al navegador de ese fragmento de código JSX:
function component() {
return <h1>Hola</h1>;
}
const jsx = component();
console.log(jsx);
/* El objeto JSX devuelto por la función */
{
$$typeof: Symbol,
key: null,
props: { ... },
_owner: FiberNode,
_store: { ... }
}
React se encargará internamente de trabajar con ese objeto por nosotros y añadirlo al HTML real de la página, de modo que nosotros solo nos tengamos que preocupar del código que escribimos en el editor.
HTML vs JSX
Aunque pueda parecerlo, JSX no es 100% compatible con HTML, y tiene sus propias normas. Además, JSX permite evaluar código Javascript y devolverlo evaluado, lo que hace que sea mucho más cómodo a la hora de trabajar.
La idea es que con React podamos trabajar con lógica de programación y estructuras de datos en Javascript antes del return
, y luego al devolver la información, se devuelva el código JSX para construir el HTML.
En cierta forma, la forma de pensar al trabajar con React es crear funciones que devuelven código JSX, y que se utilizarán como si fueran una etiqueta HTML. Veamos ahora un ejemplo donde un código HTML correcto no funcionaría en React:
export function App() {
/* Aquí iría nuestra lógica Javascript */
return (
<div>
<p>¡Hola, Manz! <br> ¿Qué tal estás?</p>
</div>
);
}
Este fragmento de código tiene una etiqueta HTML <br>
que no requiere cierre. Esto en HTML es correcto, sin embargo, React te dará error ya que se espera que todas las etiquetas HTML se cierren. Hay dos formas de solucionarlo en React:
- 1️⃣ Escribir una etiqueta de cierre
</br>
. ❌ Correcto en React pero incorrecto en HTML puro. - 2️⃣ «Autocerrar» la etiqueta sin cierre
<br />
. ✅ Válida en HTML (heredado de XHTML).
Lo mismo ocurre con otras etiquetas HTML que no requieren cierre como <img>
, <hr>
, <meta>
, <link>
, <input>
, <source>
, <track>
, <base>
, etc.
Observa que cuando tenemos fragmentos JSX muy extensos, de forma opcional se puede envolver todo en paréntesis para mejorar la legibilidad.
Javascript en JSX
La sintaxis JSX es inteligente y nos permite añadir código Javascript de múltiples formas, adaptándose automáticamente. Dos ejemplos de ello:
- El
name
lo insertamos literalmente en el párrafo<p>
, por lo que se genera como texto. - El
styles
contiene varias propiedades CSS. JSX es lo suficientemente inteligente para entender que lo estamos asociando a estilos en linea, por lo que lo convierte al formato que necesita por nosotros:
export function App() {
const name = "Manz";
const styles = {
background: "indigo",
color: "white",
padding: "5px 15px"
};
return (<div style={styles}>
<p>¡Hola, {name}!</p>
</div>);
}
<!-- Código HTML generado -->
<div style="background:indigo;color:white;padding:5px 15px">
<p>¡Hola, Manz!</p>
</div>
Cuidado: Esta no es la forma adecuada de manejar estilos en React. Es sólo un ejemplo. Más adelante veremos formas adecuadas de gestionar los estilos CSS desde React.
Eventos JSX
Al estar utilizando Javascript junto a nuestro JSX, podemos utilizar toda la potencia de Javascript para generar nuestro HTML, y no estamos limitados a hacer algo estático. Podemos interpolar variables, usar condicionales, funciones dentro de nuestra función, bucles, eventos, etc.
Observa que en este caso, hemos creado una función action
que muestra un mensaje. Si miramos el código JSX del return
, observarás que hemos creado un <button>
que cuando se pulsa (onClick
) se ejecuta la función action
:
export function App() {
const action = () => {
alert("¡Hola! ¡Has hecho click!");
}
return (<button onClick={action}>Click me!</button>);
}
Analiza detenidamente que en lugar de indicar un action
definida anteriormente.
Veamos ahora un caso un poco más avanzado, donde queremos utilizar parámetros en la función. En este caso, en lugar de usar action
definimos una función flecha que llama a la función y le pasa los parámetros deseados:
export function App() {
const action = (name) => {
alert(`¡Hola! ¡Has hecho click, ${name}!`);
}
return (
<div>
<button onClick={() => action("Manz")}>Click me, Manz!</button>
<button onClick={() => action("John")}>Click me, John!</button>
</div>
);
}
Al crear dos botones, hemos añadido un elemento <div>
padre para agruparlos. React tiene una limitación en JSX, y es que siempre debe haber un elemento padre, no pueden existir varios.
Si quieres profundizar en los eventos JSX de React, hablaremos de ellos un poco más adelante, en la sección Manejando eventos en JSX.
Fragmentos JSX
Es posible, que en el caso del ejemplo anterior, no queramos utilizar un elemento <div>
padre porque no queremos añadir contenedores innecesarios al DOM, o porque nos complicaría el diseño CSS. En lugar de utilizar <div>
podemos utilizar fragmentos JSX:
export function App() {
/* ... */
return (
<>
<button onClick={() => action("Manz")}>Click me, Manz!</button>
<button onClick={() => action("John")}>Click me, John!</button>
</>
);
}
Estos símbolos <>
y </>
generan un HTML más compacto, sin añadir ese elemento padre <div>
.