Compound Components
Padrão de composição em React detalhado a partir de advanced-react. Um
compound component expõe um componente-pai e subcomponentes que compartilham
estado implícito via Context, em vez de receberem dezenas de props.
O problema que resolve
Uma API “monolítica” com muitas props (<Select options labelKey valueKey renderOption ... />) é rígida e difícil de estender. O compound component
inverte isso: o pai detém o estado, os filhos se conectam a ele.
<Tabs defaultId="a">
<Tabs.Tab id="a">Primeira</Tabs.Tab>
<Tabs.Tab id="b">Segunda</Tabs.Tab>
</Tabs>
Como funciona
- O pai cria um
Contexte guarda o estado compartilhado (memoizando ovalue). - Os subcomponentes leem esse
Contextvia hook interno. - Os filhos são anexados como propriedades estáticas do pai (
Tabs.Tab = Tab).
const TabsCtx = createContext<{ active: string; set: (id: string) => void } | null>(
null,
);
function useTabs() {
const ctx = useContext(TabsCtx);
if (!ctx) throw new Error("Tabs.Tab deve estar dentro de <Tabs>");
return ctx;
}
function Tabs({ defaultId, children }: { defaultId: string; children: ReactNode }) {
const [active, set] = useState(defaultId);
const value = useMemo(() => ({ active, set }), [active]); // identidade estável
return <TabsCtx.Provider value={value}>{children}</TabsCtx.Provider>;
}
function Tab({ id, children }: { id: string; children: ReactNode }) {
const { active, set } = useTabs();
return (
<button aria-selected={active === id} onClick={() => set(id)}>
{children}
</button>
);
}
Tabs.Tab = Tab;
Quando usar (e quando não)
- ✅ Boa escolha para componentes com partes coordenadas:
Select,Tabs,Accordion,Menu, formulários compostos. - ⚠️ O hook interno deve lançar se usado fora do pai — falha cedo e clara.
- ⚠️ Para passar dados a fundo sem hierarquia fixa, um simples
Contextpode bastar; nem tudo precisa de subcomponentes.
Perguntas de entrevista (treinar)
- Por que memoizar o
valuedoContextno pai? - Como tipar
Tabs.Tabmantendo o autocomplete do consumidor? - Compound components vs render props — quando cada um?
Relacionadas: advanced-react · performance e Context.