JSX y componentes
En la lección anterior creaste tu primer componente React y viste que devolvía algo que se parecía mucho a HTML, pero dentro de una función JavaScript. Eso que escribiste no es HTML exactamente — es JSX, y es la forma en que React describe interfaces.
¿Qué es JSX?
JSX significa JavaScript XML. Es una extensión de sintaxis que te permite escribir "HTML" directamente dentro de JavaScript. El navegador no entiende JSX — Vite lo transforma automáticamente a llamadas de funciones JavaScript antes de enviarlo al navegador.
Cuando escribes esto:
const saludo = <h1>Hola, mundo</h1>
Vite lo convierte internamente a esto:
const saludo = React.createElement('h1', null, 'Hola, mundo')
Nadie quiere escribir React.createElement a mano. JSX hace que tu código sea legible y productivo. Piensa en JSX como un atajo elegante para describir interfaces.
Reglas de JSX
JSX se parece a HTML, pero tiene reglas propias que necesitas conocer:
1. Siempre un solo elemento raíz
Un componente solo puede devolver un elemento raíz. Esto no funciona:
// ❌ Error: dos elementos raíz
function App() {
return (
<h1>Título</h1>
<p>Párrafo</p>
)
}
Tienes dos opciones para resolverlo. Envolver en un <div>:
// ✅ Envuelto en un div
function App() {
return (
<div>
<h1>Título</h1>
<p>Párrafo</p>
</div>
)
}
O usar un Fragment (<>...</>) para no añadir un div innecesario al DOM:
// ✅ Fragment: sin div extra en el DOM
function App() {
return (
<>
<h1>Título</h1>
<p>Párrafo</p>
</>
)
}
2. className en vez de class
Como class es una palabra reservada en JavaScript, en JSX usas className:
// ❌ Esto no funciona en JSX
<div class="tarjeta">...</div>
// ✅ Usa className
<div className="tarjeta">...</div>
3. htmlFor en vez de for
El atributo for de los <label> también es palabra reservada. En JSX se usa htmlFor:
<label htmlFor="email">Correo electrónico</label>
<input id="email" type="email" />
4. Todas las etiquetas deben cerrarse
En HTML puedes escribir <img> o <br> sin cerrar. En JSX, todas las etiquetas deben cerrarse:
// ❌ Error en JSX
<img src="foto.jpg">
<br>
<input type="text">
// ✅ Correcto: etiquetas autocerradas
<img src="foto.jpg" />
<br />
<input type="text" />
5. Estilos en línea con objetos
En HTML los estilos en línea son un string. En JSX son un objeto JavaScript con propiedades en camelCase:
// HTML
<div style="background-color: red; font-size: 16px">...</div>
// JSX: objeto con camelCase
<div style={{ backgroundColor: 'red', fontSize: '16px' }}>...</div>
Las dobles llaves no son sintaxis especial: la exterior es para insertar JavaScript en JSX y la interior es el objeto literal.
Expresiones JavaScript en JSX
Dentro de las llaves {} puedes escribir cualquier expresión JavaScript. Recuerda de la sección de Lógica de Programación: una expresión es algo que produce un valor.
function ExpresionesJSX() {
const nombre = 'Astronauta'
const precio = 3.5
const productos = ['Café', 'Té', 'Chocolate']
return (
<div>
{/* Variables */}
<p>Hola, {nombre}</p>
{/* Operaciones */}
<p>Precio con IVA: {(precio * 1.21).toFixed(2)} €</p>
{/* Ternario (condicional) */}
<p>{precio > 5 ? 'Caro' : 'Asequible'}</p>
{/* Métodos de string */}
<p>{nombre.toUpperCase()}</p>
{/* Template literals */}
<p>{`Total: ${productos.length} productos`}</p>
</div>
)
}
Los comentarios en JSX se escriben así:
{/* comentario */}. No puedes usar// comentariodentro del JSX (pero sí fuera de él, en la lógica JavaScript normal).
Crear componentes
Un componente en React es una función que empieza con mayúscula y devuelve JSX. Nada más. No necesitas clases, decoradores ni sintaxis especial.
// Un componente es una función que devuelve JSX
function Saludo() {
return <h2>¡Bienvenido a Café Estelar!</h2>
}
export default Saludo
Y lo usas en otro componente como si fuera una etiqueta HTML:
import Saludo from './components/Saludo'
function App() {
return (
<div>
<Saludo />
<p>¿Qué te apetece hoy?</p>
</div>
)
}
export default App
Hay una regla de oro: los componentes siempre empiezan con mayúscula. Si escribes <saludo /> (minúscula), React lo tratará como una etiqueta HTML normal, no como un componente.
Organizar componentes en archivos
En proyectos reales, cada componente vive en su propio archivo dentro de src/components/. La convención es que el nombre del archivo coincida con el nombre del componente:
src/
├── components/
│ ├── Header.jsx
│ ├── ProductCard.jsx
│ └── Footer.jsx
├── App.jsx
└── main.jsx
Cada archivo exporta un componente y los demás lo importan cuando lo necesitan. Esto mantiene tu código modular y fácil de mantener — exactamente como aprendiste en la sección de Lógica de Programación cuando hablamos de dividir problemas en funciones.
Composición: componentes dentro de componentes
La verdadera potencia de React está en la composición: construir interfaces complejas combinando componentes simples. Piensa en piezas de LEGO — cada pieza es sencilla, pero juntas puedes construir cualquier cosa.
function Header() {
return (
<header style={{ background: '#1a1a2e', padding: '1rem', color: '#61DAFB' }}>
<h1>Café Estelar</h1>
</header>
)
}
export default Header
function ProductCard() {
return (
<div style={{ border: '1px solid #ddd', borderRadius: '8px', padding: '1rem' }}>
<h3>Café Nebulosa</h3>
<p>Un espresso con leche de avena y canela estelar.</p>
<span style={{ fontWeight: 'bold', color: '#61DAFB' }}>3.50 €</span>
</div>
)
}
export default ProductCard
import Header from './components/Header'
import ProductCard from './components/ProductCard'
function App() {
return (
<div>
<Header />
<main style={{ padding: '2rem' }}>
<h2>Nuestros cafés</h2>
<ProductCard />
<ProductCard />
<ProductCard />
</main>
</div>
)
}
export default App
Fíjate que <ProductCard /> se repite tres veces. Ahora mismo las tres tarjetas muestran lo mismo — en la siguiente lección aprenderás a usar props para pasarle datos diferentes a cada una.
Export nombrado vs export por defecto
En los ejemplos anteriores usamos export default. También puedes usar exports nombrados, que permiten exportar varios elementos desde un mismo archivo:
// Export por defecto: un solo valor por archivo
export default function Header() { ... }
// Import sin llaves
import Header from './Header'
// Export nombrado: múltiples valores por archivo
export function Header() { ... }
export function Footer() { ... }
// Import con llaves
import { Header, Footer } from './components'
En React, la convención más habitual es un componente por archivo con export por defecto. Es lo que usaremos en este curso.
Resumen
- JSX es una extensión de JavaScript que permite escribir "HTML" dentro de funciones. Vite lo transforma a JavaScript puro.
- Reglas clave: un solo elemento raíz (o Fragment),
classNameen vez declass, todas las etiquetas deben cerrarse, estilos en línea con objetos. - Las llaves
{}insertan cualquier expresión JavaScript en el JSX. - Un componente es una función con nombre en mayúscula que devuelve JSX.
- La composición permite construir interfaces complejas combinando componentes simples.
- Cada componente vive en su propio archivo en
src/components/conexport default.
En la siguiente lección aprenderás props y children — la forma de pasar datos de un componente padre a un componente hijo, haciendo que cada <ProductCard /> muestre información diferente.
Catálogo de cafés con componentes
Crea una aplicación con tres componentes separados en archivos independientes:
- Header.jsx: muestra el nombre de la cafetería ("Café Estelar") con un fondo oscuro y el texto en color React (
#61DAFB). - ProductCard.jsx: una tarjeta con el nombre de un café, su descripción y su precio. Por ahora los datos pueden estar hardcodeados dentro del componente.
- Footer.jsx: un pie de página con el texto "© 2026 Café Estelar — Todos los derechos reservados".
En App.jsx, importa los tres componentes y compón la página: Header arriba, tres ProductCard en el centro y Footer abajo. Usa un Fragment (<>...</>) como elemento raíz en al menos uno de los componentes.
lightbulb Pistas
Crea la carpeta src/components/ y dentro los tres archivos. Cada componente es una función que devuelve JSX y se exporta con export default. Para el ProductCard, puedes cambiar los datos hardcodeados en cada instancia copiando el componente o, si quieres adelantarte, mira cómo funcionan las props en la siguiente lección.