Compartilhando props em Compound Components sem usar Context API

đŸ§© TL;DR O useEnhanceChildren Ă© um hook customizado que permite injetar ou mesclar props do componente pai em seus filhos — ideal para compound components sem precisar usar Context API.
✅ Sem boilerplate, com tipagem forte e suporte a hierarquias aninh…


This content originally appeared on DEV Community and was authored by José Lucas Panizio

đŸ§© TL;DR
O useEnhanceChildren Ă© um hook customizado que permite injetar ou mesclar props do componente pai em seus filhos — ideal para compound components sem precisar usar Context API.

✅ Sem boilerplate, com tipagem forte e suporte a hierarquias aninhadas.
🔗 Veja o projeto completo no GitHub →


Quem jĂĄ criou um compound component em React sabe que compartilhar props entre o componente pai e seus filhos pode ser um processo moroso.

A abordagem mais comum Ă© usar a Context API, mas, sinceramente... sinto que estou usando uma bazuca pra matar uma formiga (overkill). Tudo o que eu queria era que os subcomponentes do Root tivessem acesso Ă s mesmas props — sem precisar criar contextos, providers e hooks para cada caso.


đŸ˜« O problema

Existem basicamente duas formas tradicionais de compartilhar props:

Repetir as props manualmente nos subcomponentes, o que Ă© nada elegante.

Usar Context API, o que Ă© poderoso, mas verboso e desnecessariamente complexo em muitos casos.

Se o Root recebe as props e envolve os subcomponentes, Ă© natural que eles tenham acesso a elas. Afinal, as props pertencem ao Root, e ele deveria ser capaz de “distribuĂ­-las” facilmente.

đŸ€” “Mas por que nĂŁo passar as props direto nos filhos?”

Boa pergunta.
Em alguns casos, faz todo sentido — por exemplo, quando o Root não usa essas props.
Mas pense em situaçÔes em que o Root também precisa delas.

Um caso clĂĄssico Ă© a prop id.
Todos os elementos React aceitam id, e ela costuma ser Ăștil em testes.
Seria Ăłtimo poder passar um Ășnico id para o Root e fazer com que cada subcomponente tivesse um ID derivado automaticamente, como:

<Root id="user">
  <Root.Header />   // id="user-header"
  <Root.Body />     // id="user-body"
  <Root.Footer />   // id="user-footer"
</Root>

Esse mesmo raciocĂ­nio vale para className, disabled, atributos data-*, entre outros.

Sim, o Context resolveria.
Mas ele adiciona boilerplate, complexidade e atĂ© listeners internos de pub/sub — algo desnecessĂĄrio quando queremos apenas espelhar props.

🧠 A solução: useEnhanceChildren

Apresento o useEnhanceChildren, um custom hook que facilita a injeção de props do componente pai nos filhos.
Ele deve ser utilizado dentro do componente Root, e conta com dois modos de operação:

1. Modo broadcast

No modo broadcast, o hook injeta o mesmo conjunto de props em todos os filhos, de forma uniforme (exceto elementos HTML nativos como <div> e <span>).

const children = useEnhanceChildren(props.children, {
  props: { disabled: true, className: 'root-child' }
});

2. Modo map

No modo map, vocĂȘ especifica quais props vĂŁo para quais filhos, utilizando o displayName de cada subcomponente.

const children = useEnhanceChildren(props.children, {
  mapProps: {
    Header: { color: 'blue' },
    Footer: { color: 'gray' },
  }
});

🔑 O displayName Ă© essencial nesse modo.
É por meio dele que o hook identifica qual subcomponente deve receber quais props:

function Header(props: { color?: string }) { /* ... */ }
Header.displayName = 'Header';

đŸ§© Type-safety com generics

VocĂȘ pode definir um generic para garantir que os nomes e as props estejam corretos, evitando erros de digitação e garantindo a inferĂȘncia de tipos adequada.

type MapProps = {
  'Card.Header': { title?: string };
  'Card.Footer': { description?: string };
};
const enhanced = useEnhanceChildren<MapProps>(children, {
  mapProps: {
    'Card.Header': { title: 'TĂ­tulo' },
    'Card.Footer': { description: 'Descrição' },
      // Erro de tipagem se vocĂȘ tentar algo errado, por exemplo:
      // 'Body': { wrongProp: true } ❌
    },
  });

đŸ§± Exemplo completo

Para visualizar o useEnhanceChildren em ação dentro de um compound component real, veja o exemplo abaixo onde o componente Card injeta suas props (title, description) diretamente nos filhos via useEnhanceChildren — sem Context, sem prop drilling manual.

import type { ReactNode, ComponentPropsWithoutRef } from 'react';
import { useEnhanceChildren } from '@/hooks/useEnhanceChildren';

type CardProps = {
  title: string;
  description: string;
  children: ReactNode; // children serĂĄ automaticamente omitido pelo hook
};

/*
type CardMapProps = {
  'Card.Header': { title: string };
  'Card.Footer': { description: string };
};
*/

export function Card({ children, ...props }: CardProps) {
  const enhancedChildren = useEnhanceChildren<CardProps>(children, {
    props, // modo broadcast
  });

  /*
  const enhancedChildren = useEnhanceChildren(children, {
    mapProps: { // modo map
      'Card.Header': { title: props.title },
      'Card.Footer=': { description: props.description },
    }, 
  });
  */

  return (
    <div>
      {enhancedChildren}
    </div>
  );
}

// ----------------------
// Card.Header
// ----------------------
type CardHeaderProps = ComponentPropsWithoutRef<'header'> & {
  title?: string;
};

Card.Header = Object.assign(
  ({ title, ...rest }: CardHeaderProps) => (
    <header {...rest}>
      {title}
    </header>
  ),
  { displayName: 'Card.Header' },
);

// ----------------------
// Card.Body
// ----------------------
type CardBodyProps = ComponentPropsWithoutRef<'main'>;

Card.Body = Object.assign(
  ({ children, ...rest }: CardBodyProps) => (
    <main {...rest}>
      {children}
    </main>
  ),
  { displayName: 'Card.Body' },
);

// ----------------------
// Card.Footer
// ----------------------
type CardFooterProps = ComponentPropsWithoutRef<'footer'> & {
  description?: string;
};

Card.Footer = Object.assign(
  ({ description, ...rest }: CardFooterProps) => (
    <footer {...rest}>
      {description}
    </footer>
  ),
  { displayName: 'Card.Footer' },
);

E seu uso na prĂĄtica ficaria assim:

<Card title="Título principal" description="Descrição resumida">
  <Card.Header />
  <Card.Body>
    <p>ConteĂșdo interno do card.</p>
  </Card.Body>
  <Card.Footer />
</Card>

Recursos e comportamento

✅ Recursividade: percorre hierarquias aninhadas — netos, bisnetos e tataranetos tambĂ©m recebem as props.
✅ PrecedĂȘncia correta: props passadas diretamente nos filhos tĂȘm prioridade (nĂŁo sĂŁo sobrescritas).
✅ Ignora elementos HTML nativos.
✅ Suporte a TypeScript forte: overloads e união discriminada para os modos map e broadcast.
✅ Memoização interna: evita re-renderizaçÔes desnecessĂĄrias.

ConclusĂŁo

O useEnhanceChildren nasceu da necessidade de simplificar algo bem específico: compartilhar props do Root com seus filhos em compound components — sem recorrer à complexidade da Context API.

Mas, embora tenha sido pensado para esse cenĂĄrio, acredito que ele pode ser Ăștil em outros contextos onde hĂĄ herança natural de props. E, claro, ainda hĂĄ espaço para evoluir — tanto em recursos quanto em ergonomia.

O hook não substitui o Context, mas preenche com elegùncia o espaço entre o prop drilling manual e o context overkill.

Se vocĂȘ trabalha com compound components, recomendo experimentar — e, por que nĂŁo, contribuir com melhorias.
💬 DĂșvidas, crĂ­ticas e sugestĂ”es tambĂ©m sĂŁo muito bem-vindas.

🔗 Veja o projeto completo no GitHub →


This content originally appeared on DEV Community and was authored by José Lucas Panizio


Print Share Comment Cite Upload Translate Updates
APA

José Lucas Panizio | Sciencx (2025-11-02T20:24:26+00:00) Compartilhando props em Compound Components sem usar Context API. Retrieved from https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/

MLA
" » Compartilhando props em Compound Components sem usar Context API." JosĂ© Lucas Panizio | Sciencx - Sunday November 2, 2025, https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/
HARVARD
JosĂ© Lucas Panizio | Sciencx Sunday November 2, 2025 » Compartilhando props em Compound Components sem usar Context API., viewed ,<https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/>
VANCOUVER
JosĂ© Lucas Panizio | Sciencx - » Compartilhando props em Compound Components sem usar Context API. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/
CHICAGO
" » Compartilhando props em Compound Components sem usar Context API." JosĂ© Lucas Panizio | Sciencx - Accessed . https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/
IEEE
" » Compartilhando props em Compound Components sem usar Context API." JosĂ© Lucas Panizio | Sciencx [Online]. Available: https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/. [Accessed: ]
rf:citation
» Compartilhando props em Compound Components sem usar Context API | JosĂ© Lucas Panizio | Sciencx | https://www.scien.cx/2025/11/02/compartilhando-props-em-compound-components-sem-usar-context-api/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.