Children y composición
HTML siempre ha funcionado anidando: un <select> envuelve sus <option>s, un <ul> envuelve sus <li>s, un <button> envuelve su etiqueta. El elemento del medio es hijo del elemento que lo rodea, y los dos trabajan juntos para hacer lo que ves. Los componentes de React pueden funcionar igual. En lugar de pasar todo a través de props nombradas, un componente puede envolver contenido de la misma forma que los elementos nativos lo hacen, y esa única idea es lo que separa un componente que configuras de un componente que compones.
Este capítulo desarrolla la idea de la forma que lo hace el curso, a través de un Button para una librería de componentes: primero children, luego prop spreading, y después los detalles finales que hacen un componente reutilizable en la práctica.
Children como interfaz
El capítulo Props introdujo children: el contenido entre las etiquetas de apertura y cierre de un componente llega como una prop con ese nombre. Lo que te ganas para reutilización es más de lo que parece.
function Button({ children }) {
return <button>{children}</button>
}
// uso: <Button>Comprar ahora</Button>El componente decide dónde renderizar los children, y quien lo usa decide qué son. Compáralo con una prop text, que funciona hasta que quien la usa quiere algo más allá de una cadena. Con children, nada detiene al usuario de pasar más que texto:
// uso:
// <Button>
// <CartIcon />
// Comprar ahora
// </Button>Un icono a la izquierda de la etiqueta, sin prop icon, sin opción iconPosition="left", sin anticipación del autor del componente en absoluto. ¿Quieres el icono a la derecha? Muévelo al otro lado del texto. Cada prop de configuración que el autor habría tenido que inventar se disuelve en quien la usa escribiendo el markup que quiso.
Reenviando el resto de las props
Un Button que renderiza un <button> nativo tiene un segundo problema: eventos. Cuando quien lo usa escribe <Button onClick={...}>, ese onClick es una prop personalizada que llega a tu componente; nada sucede a menos que el componente la reenvíe al verdadero <button> debajo. Podrías reenviar onClick a mano, luego onDoubleClick, luego style, luego className, y aún así nunca cubrirías todo lo que un button nativo acepta. La sintaxis spread los reenvía todos a la vez:
function Button({ children, ...rest }) {
return <button {...rest}>{children}</button>
}Desestructura las props que tu componente realmente maneja, recopila todo lo demás con sintaxis rest, y expande el rest sobre el elemento subyacente. Cada atributo válido de button que quien la usa pase, incluyendo manejadores de eventos, va donde debe ir. Las props que tu componente inventa para sí mismo (una variant, digamos) se desestructuran para que nunca lleguen al elemento del DOM.
Haciendo espacio para tu propia API
Los componentes reutilizables usualmente agregan opciones encima del elemento nativo. El button del curso toma un size ("sm" o "lg") y una variant ("success", "warning", "danger"), cada uno mapeando a una clase CSS:
function Button({ children, size, variant, className, ...rest }) {
const sizeClass = size ? `button-${size}` : ''
const variantClass = variant ? `button-${variant}` : ''
const allClasses = [sizeClass, variantClass, className].filter(Boolean).join(' ')
return (
<button className={allClasses} {...rest}>
{children}
</button>
)
}Esa fusión evita un bug sutil. Si el componente establece className y quien lo usa también pasa una, lo que llega último al elemento gana: expande el rest después de tu className y la clase de quien la usa sobrescribe silenciosamente la tuya; expándelo antes y la tuya sobrescribe la de ellos. Desestructurar className y fusionar las cadenas tú mismo es la solución. Librerías como clsx o classnames existen para hacer exactamente esta fusión una vez que las condiciones se multiplican.
children no necesita una prop text, una prop icon, y una prop icon-position. Quien la use escribe el icono y el texto dentro de las etiquetas en el orden que quiere, y el Button deja ese contenido donde corresponde. Anidamiento, la cosa que HTML siempre ha hecho, es también el mejor truco de React para reutilización.
Siguiente: Compound components, donde un componente se convierte en varios que trabajan juntos.

