UNPKG

opencode-agent-kit

Version:

Multi-stack OpenCode agent toolkit — 33+ specialized AI agents, 200+ skills, 46 commands, 8 MCP servers (Nuxt, React, Node.js, Laravel, CI3, Android, Flutter, DevOps, SEO, SonarQube, and more)

113 lines (98 loc) 2.6 kB
--- title: Use Compound Components impact: HIGH impactDescription: enables flexible composition without prop drilling tags: composition, compound-components, architecture --- ## Use Compound Components Structure complex components as compound components with a shared context. Each subcomponent accesses shared state via context, not props. Consumers compose the pieces they need. **Incorrect (monolithic component with render props):** ```tsx function Composer({ renderHeader, renderFooter, renderActions, showAttachments, showFormatting, showEmojis, }: Props) { return ( <form> {renderHeader?.()} <Input /> {showAttachments && <Attachments />} {renderFooter ? ( renderFooter() ) : ( <Footer> {showFormatting && <Formatting />} {showEmojis && <Emojis />} {renderActions?.()} </Footer> )} </form> ) } ``` **Correct (compound components with shared context):** ```tsx const ComposerContext = createContext<ComposerContextValue | null>(null) function ComposerProvider({ children, state, actions, meta }: ProviderProps) { return ( <ComposerContext value={{ state, actions, meta }}> {children} </ComposerContext> ) } function ComposerFrame({ children }: { children: React.ReactNode }) { return <form>{children}</form> } function ComposerInput() { const { state, actions: { update }, meta: { inputRef }, } = use(ComposerContext) return ( <TextInput ref={inputRef} value={state.input} onChangeText={(text) => update((s) => ({ ...s, input: text }))} /> ) } function ComposerSubmit() { const { actions: { submit }, } = use(ComposerContext) return <Button onPress={submit}>Send</Button> } // Export as compound component const Composer = { Provider: ComposerProvider, Frame: ComposerFrame, Input: ComposerInput, Submit: ComposerSubmit, Header: ComposerHeader, Footer: ComposerFooter, Attachments: ComposerAttachments, Formatting: ComposerFormatting, Emojis: ComposerEmojis, } ``` **Usage:** ```tsx <Composer.Provider state={state} actions={actions} meta={meta}> <Composer.Frame> <Composer.Header /> <Composer.Input /> <Composer.Footer> <Composer.Formatting /> <Composer.Submit /> </Composer.Footer> </Composer.Frame> </Composer.Provider> ``` Consumers explicitly compose exactly what they need. No hidden conditionals. And the state, actions and meta are dependency-injected by a parent provider, allowing multiple usages of the same component structure.