95 lines
2.3 KiB
Markdown
95 lines
2.3 KiB
Markdown
---
|
|
title: Create Explicit Component Variants
|
|
impact: MEDIUM
|
|
impactDescription: self-documenting code, no hidden conditionals
|
|
tags: composition, variants, architecture
|
|
---
|
|
|
|
## Create Explicit Component Variants
|
|
|
|
Instead of one component with many boolean props, create explicit variant
|
|
components. Each variant composes the pieces it needs. The code documents
|
|
itself.
|
|
|
|
**Incorrect (one component, many modes):**
|
|
|
|
```tsx
|
|
// What does this component actually render?
|
|
<Composer isThread isEditing={false} channelId="abc" showAttachments showFormatting={false} />
|
|
```
|
|
|
|
**Correct (explicit variants):**
|
|
|
|
```tsx
|
|
// Immediately clear what this renders
|
|
<ThreadComposer channelId="abc" />
|
|
|
|
// Or
|
|
<EditMessageComposer messageId="xyz" />
|
|
|
|
// Or
|
|
<ForwardMessageComposer messageId="123" />
|
|
```
|
|
|
|
Each implementation is unique, explicit and self-contained. Yet they can each
|
|
use shared parts.
|
|
|
|
**Implementation:**
|
|
|
|
```tsx
|
|
function ThreadComposer({ channelId }: { channelId: string }) {
|
|
return (
|
|
<ThreadProvider channelId={channelId}>
|
|
<Composer.Frame>
|
|
<Composer.Input />
|
|
<AlsoSendToChannelField channelId={channelId} />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.Submit />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</ThreadProvider>
|
|
);
|
|
}
|
|
|
|
function EditMessageComposer({ messageId }: { messageId: string }) {
|
|
return (
|
|
<EditMessageProvider messageId={messageId}>
|
|
<Composer.Frame>
|
|
<Composer.Input />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.CancelEdit />
|
|
<Composer.SaveEdit />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</EditMessageProvider>
|
|
);
|
|
}
|
|
|
|
function ForwardMessageComposer({ messageId }: { messageId: string }) {
|
|
return (
|
|
<ForwardMessageProvider messageId={messageId}>
|
|
<Composer.Frame>
|
|
<Composer.Input placeholder="Add a message, if you'd like." />
|
|
<Composer.Footer>
|
|
<Composer.Formatting />
|
|
<Composer.Emojis />
|
|
<Composer.Mentions />
|
|
</Composer.Footer>
|
|
</Composer.Frame>
|
|
</ForwardMessageProvider>
|
|
);
|
|
}
|
|
```
|
|
|
|
Each variant is explicit about:
|
|
|
|
- What provider/state it uses
|
|
- What UI elements it includes
|
|
- What actions are available
|
|
|
|
No boolean prop combinations to reason about. No impossible states.
|