Filhos e composição
HTML sempre funcionou por aninhamento: um <select> envolve seus <option>s, um <ul> envolve seus <li>s, um <button> envolve seu rótulo. O elemento do meio é filho do elemento ao seu redor, e os dois trabalham juntos para criar aquilo que você vê. Componentes React components podem funcionar da mesma forma. Em vez de passar tudo através de props nomeadas, um componente pode envolver o conteúdo da forma como elementos nativos fazem, e essa ideia única é o que separa um componente que você configura de um componente que você compõe.
Este capítulo constrói o raciocínio do mesmo jeito que o curso faz, através de um Button para uma biblioteca de componentes: primeiro filhos, depois espalhamento de props, depois os detalhes finais que tornam um componente reutilizável na prática.
Filhos como uma interface
O capítulo Props introduziu children: conteúdo entre as tags de abertura e fechamento de um componente chega como uma prop com esse nome. O que isso te proporciona para reutilização é maior do que parece.
function Button({ children }) {
return <button>{children}</button>
}
// uso: <Button>Comprar agora</Button>O componente decide onde os filhos renderizam, e quem chama o componente decide o que eles são. Compare isso com uma prop text, que funciona até o ponto em que quem chama quer algo além de uma string. Com children, nada impede que passem mais do que texto:
// uso:
// <Button>
// <CartIcon />
// Comprar agora
// </Button>Um ícone à esquerda do rótulo, sem prop icon, sem opção iconPosition="left", sem nenhuma antecipação do autor do componente. Quer o ícone à direita? Mova-o para o outro lado do texto. Toda prop de configuração que o autor teria precisado inventar desaparece e quem chama escreve simplesmente o markup que quis.
Encaminhando o resto das props
Um Button que renderiza um <button> nativo tem um segundo problema: eventos. Quando quem chama escreve <Button onClick={...}>, esse onClick é uma prop customizada chegando no seu componente; nada acontece a menos que o componente o passe para o verdadeiro <button> por baixo. Você poderia encaminhar onClick manualmente, depois onDoubleClick, depois style, depois className, e ainda assim nunca cobrir tudo que um button nativo aceita. A sintaxe de espalhamento encaminha tudo de uma vez:
function Button({ children, ...rest }) {
return <button {...rest}>{children}</button>
}Desestruture as props que seu componente realmente lida, coleta tudo o mais com a sintaxe rest, e espalhe o rest no elemento subjacente. Toda atributo válido de button que quem chama passa, incluindo event handlers, chega onde deveria. Props que seu componente inventa para si mesmo (um variant, digamos) saem da desestruturação para nunca alcançar o elemento do DOM.
Abrindo espaço para sua própria API
Componentes reutilizáveis geralmente adicionam opções por cima do elemento nativo. O button do curso recebe um size ("sm" ou "lg") e um variant ("success", "warning", "danger"), cada um mapeando para uma classe 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>
)
}Essa mesclagem evita um bug sutil. Se o componente define className e quem chama também passa uma, qualquer uma que chegar por último ao elemento vence: espalhe o rest depois de seu próprio className e a classe de quem chama silenciosamente sobrescreve a sua; espalhe antes e a sua sobrescreve a deles. Desestruturar className e mesclar as strings você mesmo é a solução. Bibliotecas como clsx ou classnames existem para fazer exatamente essa mesclagem quando as condições se multiplicam.
children não precisa de uma prop text, uma prop icon, e uma prop icon-position. Quem quer usá-lo escreve o ícone e o texto dentro das tags na ordem que quer, e o Button coloca esse conteúdo onde pertence. Aninhamento, a coisa que HTML sempre fez, é também o melhor truque do React para reutilização.
Próximo: Compound components, onde um componente se torna vários que trabalham juntos.

