En el artículo anterior creamos nuestro primer componente Saludo. Funcionaba, pero tenía un problema grave de diseño: era estático.
Es decir, siempre saludaba a “Luis”. Pero si quisiéramos saludar a “María”, tendríamos que crear otro componente distinto (Y… como que no seria muy practico).
En JavaScript (y casi cualquier lenguaje), cuando queremos que una función sea dinámica, le pasamos argumentos.
El equivalente en Componentes de React, es que cuando queremos que un componente sea dinámico le pasamos Props (abreviatura de Propiedades).
Las Props son el mecanismo fundamental que tiene React para pasar datos de un componente padre a un componente hijo.
Pasando datos (El padre)
Imaginad que estamos en App.jsx (el padre) y queremos usar nuestro componente Saludo (el hijo) varias veces, pero con nombres distintos.
Es decir, básicamente lo que nos gustaría es hacer esto, usando una sintaxis idéntica a los atributos HTML que ya conocéis:
// src/App.jsx
import Saludo from './components/Saludo';
function App() {
return (
<div>
{/* Pasamos la prop "nombre" con un valor string */}
<Saludo nombre="Luis" />
<Saludo nombre="María" />
<Saludo nombre="Carlos" />
</div>
)
}
En este momento, React coge todos esos atributos que hemos escrito (nombre="Luis") y los empaqueta en un solo objeto.
Recibiendo datos (El Hijo)
Ahora vamos al componente Saludo.jsx. React coge ese objeto que ha creado con nuestros atributos, y lo inyecta como el primer argumento de la función del componente.
Simplemente por convención, a este argumento lo llamamos props.
// src/components/Saludo.jsx
// Opción 1: Recibiendo el objeto props entero
function Saludo(props) {
// props es { nombre: "Luis" }
return <h2>Hola, {props.nombre}!</h2>;
}
export default Saludo;
Acabamos de hacer nuestro componente reutilizable. El componente ya no “sabe” qué nombre va a pintar, simplemente pinta lo que le manden.
Destructuring Props
Aunque props.nombre funciona, en el mundo real rara vez veréis código escrito así. Es verboso y repetitivo escribir props. todo el rato.
En su lugar, generalmente utilizamos el Destructuring de objetos de JavaScript directamente en la firma de la función.
// Opción 2: Destructuring (Recomendado)
function Saludo({ nombre }) {
// Extraemos "nombre" directamente
return <h2>Hola, {nombre}!</h2>;
}
Esto es bastante más limpio. Además, nos permite ver de un vistazo qué datos necesita el componente para funcionar sin tener que leer todo el código buscando props.algo.
Pasando otros tipos de datos
Hasta ahora hemos pasado un string literal ("Luis"). Pero las props pueden ser cualquier cosa: números, booleanos, arrays, objetos, funciones e incluso otros componentes JSX.
Pero si el valor no es un string literal, debemos usar las llaves { }.
<Producto
titulo="Laptop Gaming" // String
precio={1200} // Número
enStock={true} // Booleano
tags={['asus', 'tech']} // Array
detalles={{ peso: '2kg' }} // Objeto
/>
En el componente hijo lo recibiríamos de la misma forma:
function Producto({ titulo, precio, enStock, tags, detalles }) {
return (
<div className="card">
<h3>{titulo}</h3>
<p>Precio: {precio}€</p>
<p>{enStock ? 'Disponible' : 'Agotado'}</p>
<small>Peso: {detalles.peso}</small>
</div>
);
}
Fijaos en el booleano enStock. React no renderiza true o false en pantalla por defecto. Por eso usamos un ternario para mostrar texto.
Props por defecto (Default Props)
¿Qué pasa si usamos el componente <Saludo /> sin pasarle el nombre?
// App.jsx
<Saludo /> // No pasamos "nombre"
Dentro del componente, nombre será undefined. El resultado será “Hola, !” o un error si intentamos manipular esa variable.
Para evitar esto, podemos definir valores por defecto.
// src/components/Saludo.jsx
function Saludo({ nombre = "Invitado" }) {
return <h2>Hola, {nombre}!</h2>;
}
Ahora, si no le pasamos nada, nombre valdrá “Invitado” automáticamente. Más robusto ante fallos.
Antiguamente se usaba una propiedad llamada defaultProps, pero hoy en día usamos la sintaxis nativa de parámetros por defecto de ES6:
Las props son inmutables
Las props son de solo lectura. Un componente NUNCA debe modificar sus propias props.
function Saludo({ nombre }) {
nombre = "Pepe"; // ¡ERROR! No modifiques lo que te llega
return <h1>{nombre}</h1>
}
React sigue un flujo de datos Unidireccional (One-Way Data Flow). Los datos fluyen hacia abajo, del padre al hijo. El hijo recibe datos y los pinta.
Si el hijo necesita cambiar algo, no cambia la prop; debe pedirle al padre que cambie el valor y se lo vuelva a enviar.
Esta restricción es una de las característias que las aplicaciones de React sean predecibles y fáciles de depurar (y un infierno a veces también).
