Files
gemini-nexus/.agent/skills/vercel-composition-patterns/rules/architecture-compound-components.md
T
AngeloooooandDraculabo 8ed4593f73 Refactor Gemini model display: filter old versions, group low/high pкo, and improve naming (#114)
* Refactor Gemini model display: filter old versions, group low/high pro, and improve naming

* Fix potential negative minutes and refine Gemini 3 Pro grouping logic based on PR feedback

* The account change process has been sped up

* Address PR review: enhance error message and parameterize polling interval in process handler

* Address PR review: fix potential race condition in database backup logic

* fix: prevent renderer white screen and harden sentry gating

* feat:  localize model labels

* chore: enable hoisted node-linker

* chore: ignore .agent/.claude/.codex in prettier

---------

Co-authored-by: Draculabo <[email protected]>
2026-02-19 19:37:30 +08:00

109 lines
2.5 KiB
Markdown

---
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.