2.2 KiB
2.2 KiB
title, impact, impactDescription, tags
| title | impact | impactDescription | tags |
|---|---|---|---|
| Avoid Boolean Prop Proliferation | CRITICAL | prevents unmaintainable component variants | composition, props, architecture |
Avoid Boolean Prop Proliferation
Don't add boolean props like isThread, isEditing, isDMThread to customize
component behavior. Each boolean doubles possible states and creates
unmaintainable conditional logic. Use composition instead.
Incorrect (boolean props create exponential complexity):
function Composer({
onSubmit,
isThread,
channelId,
isDMThread,
dmId,
isEditing,
isForwarding,
}: Props) {
return (
<form>
<Header />
<Input />
{isDMThread ? (
<AlsoSendToDMField id={dmId} />
) : isThread ? (
<AlsoSendToChannelField id={channelId} />
) : null}
{isEditing ? <EditActions /> : isForwarding ? <ForwardActions /> : <DefaultActions />}
<Footer onSubmit={onSubmit} />
</form>
);
}
Correct (composition eliminates conditionals):
// Channel composer
function ChannelComposer() {
return (
<Composer.Frame>
<Composer.Header />
<Composer.Input />
<Composer.Footer>
<Composer.Attachments />
<Composer.Formatting />
<Composer.Emojis />
<Composer.Submit />
</Composer.Footer>
</Composer.Frame>
);
}
// Thread composer - adds "also send to channel" field
function ThreadComposer({ channelId }: { channelId: string }) {
return (
<Composer.Frame>
<Composer.Header />
<Composer.Input />
<AlsoSendToChannelField id={channelId} />
<Composer.Footer>
<Composer.Formatting />
<Composer.Emojis />
<Composer.Submit />
</Composer.Footer>
</Composer.Frame>
);
}
// Edit composer - different footer actions
function EditComposer() {
return (
<Composer.Frame>
<Composer.Input />
<Composer.Footer>
<Composer.Formatting />
<Composer.Emojis />
<Composer.CancelEdit />
<Composer.SaveEdit />
</Composer.Footer>
</Composer.Frame>
);
}
Each variant is explicit about what it renders. We can share internals without sharing a single monolithic parent.