react-que-son-y-como-usar-props-children

Qué son y cómo usar Children en React

  • 3 min

En el capítulo anterior vimos cómo pasar información de padres a hijos mediante Props. Le pasábamos un texto, un número o un booleano para configurar el componente.

Pero, ¿qué pasa si queremos pasar otro componente o código HTML dentro de otro? Por ejemplo, imagina que quieres crear un componente <Card>, que envuelve un contenido

Ahora no queremos configurar solo el título, o esta variable o aquella. Queremos meter dentro un fragmento HTML: un formulario, un texto, una imagen, un div con tres botones… cualquier cosa.

Para esto, React utiliza un modelo de Composición, que se apoya en una prop especial llamada children.

¿Cuando usar Children?

Siempre que os encontréis pasando props para “pintar cosas” (ej: textButton="Enviar", iconButton="save.svg"), preguntaos si no sería más limpio usar children (<Button>Enviar <Icon /></Button>).

La prop children

React tiene una regla especiallo que escribas entre de las etiquetas de apertura y cierre de un componente se pasa automáticamente en la prop children.

Miremos este ejemplo:

// Uso del componente
<Boton>
  <span>Guardar</span>
  <IconoDiskette />
</Boton>
Copied!

Internamente, React coge ese <span> y ese <IconoDiskette />, los empaqueta y se los entrega al componente Boton dentro de props.children.

Implementando el contenedor

Para que el componente “pinte” lo que le hemos pasado, tenemos que renderizar explícitamente esa prop children en el lugar donde queremos que aparezca el contenido.

Es como dejar un hueco vacío (un slot) reservado.

// Definición del componente
function Boton(props) {
  return (
    <button className="mi-clase-boton">
      {/* Aquí volcamos el contenido que nos pasen */}
      {props.children}
    </button>
  );
}
Copied!

Si os olvidáis de poner {props.children} en el JSX del hijo, el contenido se ignorará y no se verá nada.

El patrón de “Cajas Genéricas”

El uso más potente de esto es crear componentes estructurales que no saben qué contenido van a tener, solo saben cómo se ve el contenedor.

El ejemplo clásico es una Card que hemos mencionado antes:

// Components/Card.jsx
export default function Card({ children, titulo }) {
  return (
    <div className="card-borde-sombra">
      <div className="card-header">
        <h2>{titulo}</h2>
      </div>
      
      <div className="card-body">
        {/* El "agujero" donde irá el contenido variable */}
        {children}
      </div>
    </div>
  );
}
Copied!

Ahora podemos reutilizar esta tarjeta para cosas totalmente distintas:

// Uso 1: Perfil de Usuario
<Card titulo="Usuario">
  <img src="avatar.jpg" />
  <p>Nombre: Luis</p>
</Card>

// Uso 2: Mensaje de error
<Card titulo="Error Crítico">
  <p>Ha ocurrido un error en el sistema.</p>
  <button>Reintentar</button>
</Card>
Copied!

La Card no sabe qué hay dentro. No le importa. Solo se encarga del borde, la sombra y el título. Eso es Composición.

Múltiples Slots

A veces, un solo hueco (children) no es suficiente. Imaginad un componente <Layout> que necesita:

  1. Una barra lateral (Sidebar).
  2. Un contenido principal.
  3. Un pie de página (Footer).

En otros frameworks esto se llama “Named Slots”. En React, simplemente recordamos que las props pueden ser cualquier cosa, incluido JSX.

Podemos pasar componentes enteros como si fueran props normales.

// Components/Layout.jsx
function Layout({ sidebar, content, footer }) {
  return (
    <div className="layout-grid">
      <aside className="zona-sidebar">{sidebar}</aside>
      
      <main className="zona-main">{content}</main>
      
      <footer className="zona-footer">{footer}</footer>
    </div>
  );
}

// Uso
function App() {
  return (
    <Layout
      sidebar={<MenuNavegacion />}
      content={<ListaDeProductos />}
      footer={<p>© 2024 Mi Empresa</p>}
    />
  );
}
Copied!

Este patrón evita tener que pasar cientos de props de configuración (sidebarColor, sidebarTitle, footerText…). En su lugar, simplemente pasas el componente ya montado y el Layout solo decide dónde colocarlo.