Props y children
En la lección anterior creaste componentes, pero todos mostraban datos fijos. Tres <ProductCard /> mostraban exactamente el mismo café. Eso no es muy útil. Necesitas una forma de pasarle datos diferentes a cada componente — y para eso existen las props.
Si recuerdas la sección de Lógica de Programación, las funciones recibían parámetros para trabajar con datos diferentes cada vez que se llamaban. Las props son exactamente lo mismo: los parámetros de un componente React.
¿Qué son las props?
Las props (abreviatura de "properties") son la forma de pasar datos de un componente padre a un componente hijo. Se pasan como atributos en el JSX y se reciben como un objeto en la función del componente.
// El componente recibe props como parámetro
function ProductCard(props) {
return (
<div className="card">
<h3>{props.nombre}</h3>
<p>{props.descripcion}</p>
<span className="precio">{props.precio} €</span>
</div>
)
}
export default ProductCard
import ProductCard from './components/ProductCard'
function App() {
return (
<div>
<h1>Café Estelar</h1>
<ProductCard
nombre="Café Nebulosa"
descripcion="Espresso con leche de avena y canela estelar."
precio={3.5}
/>
<ProductCard
nombre="Latte Cósmico"
descripcion="Café con leche, vainilla y polvo de estrellas."
precio={4.2}
/>
<ProductCard
nombre="Mocha Intergaláctico"
descripcion="Chocolate negro, espresso y crema de la Vía Láctea."
precio={4.8}
/>
</div>
)
}
export default App
Cada <ProductCard /> recibe datos diferentes a través de las props, pero usa el mismo componente. Un componente, tres resultados distintos. Eso es reutilización.
Desestructurar props
Escribir props.nombre, props.descripcion, props.precio es repetitivo. La forma estándar en React es desestructurar las props directamente en el parámetro de la función — igual que hacías con objetos en JavaScript:
// ✅ Desestructuración: más limpio y directo
function ProductCard({ nombre, descripcion, precio }) {
return (
<div className="card">
<h3>{nombre}</h3>
<p>{descripcion}</p>
<span className="precio">{precio} €</span>
</div>
)
}
export default ProductCard
Esto es equivalente a lo anterior pero más conciso. Verás esta sintaxis en prácticamente todo el código React del mundo real.
Props por defecto
A veces quieres que una prop tenga un valor si el padre no la pasa. Puedes definir valores por defecto directamente en la desestructuración:
function ProductCard({ nombre, descripcion, precio = 0, disponible = true }) {
return (
<div className="card" style={{ opacity: disponible ? 1 : 0.5 }}>
<h3>{nombre}</h3>
<p>{descripcion}</p>
<span className="precio">{precio.toFixed(2)} €</span>
{!disponible && <p className="agotado">Agotado</p>}
</div>
)
}
export default ProductCard
// precio usa el valor por defecto (0), disponible usa el suyo (true)
<ProductCard nombre="Agua Estelar" descripcion="Agua del manantial de Orión." />
// Aquí pasamos disponible como false
<ProductCard
nombre="Café Eclipse"
descripcion="Edición limitada."
precio={6.0}
disponible={false}
/>
Tipos de datos en props
Las props pueden ser de cualquier tipo de JavaScript. Los strings se pasan con comillas y el resto con llaves:
// String: con comillas
<Componente nombre="Astronauta" />
// Número: con llaves
<Componente precio={3.5} />
// Booleano: con llaves (o solo el nombre para true)
<Componente disponible={true} />
<Componente disponible /> {/* equivale a true */}
// Array: con llaves
<Componente ingredientes={['café', 'leche', 'canela']} />
// Objeto: con llaves (dobles llaves = llave JSX + objeto literal)
<Componente estilo={{ color: 'red', fontSize: '14px' }} />
// Función: con llaves
<Componente onClick={() => alert('¡Hola!')} />
Las props son de solo lectura
Esto es fundamental: un componente nunca debe modificar sus props. Las props son datos que vienen del padre y el hijo solo puede leerlas.
function ProductCard({ precio }) {
// ❌ NUNCA hagas esto
precio = precio * 1.21
// ✅ Crea una nueva variable
const precioConIva = precio * 1.21
return <p>{precioConIva} €</p>
}
Si necesitas un dato que cambie, eso es estado — lo veremos en la siguiente lección.
Children: contenido entre etiquetas
Hay una prop especial llamada children. Es todo lo que pones entre las etiquetas de apertura y cierre de un componente:
// children es lo que va dentro de las etiquetas del componente
function Card({ children, titulo }) {
return (
<div className="card">
<h3>{titulo}</h3>
<div className="card__body">
{children}
</div>
</div>
)
}
export default Card
import Card from './components/Card'
function App() {
return (
<div>
<Card titulo="Café Nebulosa">
<p>Espresso con leche de avena y canela estelar.</p>
<span>3.50 €</span>
</Card>
<Card titulo="Oferta del día">
<p>¡2x1 en todos los lattes!</p>
<button>Ver oferta</button>
</Card>
</div>
)
}
export default App
children es perfecto para crear componentes "contenedor" que no saben de antemano qué contenido van a tener. Un componente Card, un Modal, un Layout — todos usan children para envolver contenido arbitrario.
Composición con props y children
Vamos a crear un ejemplo más completo que combine props y children:
function Badge({ texto, color = '#61DAFB' }) {
return (
<span style={{
background: color,
color: '#1a1a2e',
padding: '2px 8px',
borderRadius: '4px',
fontSize: '0.75rem',
fontWeight: 'bold'
}}>
{texto}
</span>
)
}
export default Badge
import Badge from './Badge'
function ProductCard({ nombre, descripcion, precio, categoria }) {
return (
<div className="card">
<div className="card__header">
<h3>{nombre}</h3>
<Badge texto={categoria} />
</div>
<p>{descripcion}</p>
<span className="precio">{precio.toFixed(2)} €</span>
</div>
)
}
export default ProductCard
import ProductCard from './components/ProductCard'
function App() {
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '2rem' }}>
<h1 style={{ color: '#61DAFB' }}>Café Estelar</h1>
<ProductCard
nombre="Café Nebulosa"
descripcion="Espresso con leche de avena y canela estelar."
precio={3.5}
categoria="Espresso"
/>
<ProductCard
nombre="Latte Cósmico"
descripcion="Café con leche, vainilla y polvo de estrellas."
precio={4.2}
categoria="Latte"
/>
<ProductCard
nombre="Té Supernova"
descripcion="Té verde con jengibre y miel del asteroide B-612."
precio={3.0}
categoria="Té"
/>
</div>
)
}
export default App
Fíjate en la cadena: App → ProductCard → Badge. Los datos fluyen siempre de arriba a abajo, de padre a hijo. Este flujo unidireccional es una de las ideas centrales de React y hace que tu código sea predecible — siempre sabes de dónde vienen los datos.
Resumen
- Las props son la forma de pasar datos de un componente padre a un componente hijo. Son como los parámetros de una función.
- Se reciben desestructurándolas en el parámetro de la función:
function Card({ titulo, precio }). - Puedes definir valores por defecto directamente en la desestructuración.
- Las props son de solo lectura — nunca las modifiques directamente.
- children es una prop especial que contiene todo lo que pones entre las etiquetas de apertura y cierre del componente.
- Los datos fluyen siempre de arriba a abajo (padre → hijo). Esto se llama flujo unidireccional.
En la siguiente lección aprenderás useState — el hook que permite a tus componentes tener datos que cambian con el tiempo y hacen que la interfaz reaccione.
Equipo galáctico con props y children
Crea un componente MemberCard que reciba las siguientes props: nombre, rol, avatar (URL de imagen), y activo (booleano, por defecto true). Si activo es false, la tarjeta debe mostrarse con opacidad reducida.
- Crea un componente
Sectionque reciba untituloy usechildrenpara envolver su contenido. - En
App.jsx, usaSectioncon el título "Nuestro equipo" y dentro coloca al menos tresMemberCardcon datos diferentes. Uno de ellos debe teneractivo={false}. - Para las imágenes puedes usar placeholders como
https://i.pravatar.cc/150?img=1(cambia el número para diferentes avatares).
lightbulb Pistas
Desestructura las props directamente en el parámetro: function MemberCard( nombre, rol, avatar, activo = true ). Para la opacidad condicional, usa estilos en línea: style={{ "{{" }} opacity: activo ? 1 : 0.5 {{ "}}" }}. El componente Section recibe children y lo renderiza dentro de un contenedor con un <h2> para el título.