~ min read
Too many props, it hurts π
When starting a new project, it may seem straightforward to introduce a new prop to manage a specific behavior or style in your components. While this approach works initially, as the project scales, it becomes increasingly difficult to track what each prop controls. This adds unnecessary complexity and makes the component harder to maintain in the long run.
The Problem
Let us say you have been given a design and you plan on building a reusable button component that looks something like this:
This button contains just a text and an icon to the left.
interface ButtonProps {
text: string
icon?: string
}
const Button = ({ text, icon }: ButtonProps) => {
return (
<button>
{icon ? <Icon name={ icon} size={10} />}
<span>{text}</span>
</button>
)
}
// and can be used assuch
<Button text="Add More" icon="plus" />
This is quite straightforward!
A week later the designer comes in and makes changes to the component and the component now needs to accept extra parameters, such as a right icon, left icon, and the size should be dynamic for each..
That's alot of changes π, we then decide to add extra props to accomodate these scenarios
const Button = ({ text, leftIcon, rightIcon, leftIconSize, rightIconSize }) => {
return (
<button>
{leftIcon ? <Icon name={leftIcon} size={leftIconSize} />}
<span>{text}</span>
{rightIcon ? <Icon name={rightIcon} size={rightIconSize} />}
</button>
)
}
// and can be used assuch
<Button text="Add More" leftIcon="plus" rightIcon="plus" leftIconSize={10} rightIconSize={15}/>
We now have now moved from 2 props originally to 5 props, with the potential of growing even more. π€¦πΎββοΈ
A better way: Compound Components πͺπΎ
Compound components are a composition pattern that allows us to define individual parts of a component as independent components that work together as a cohesive unit. This approach offers flexibility, enabling developers to easily include or exclude specific sections of the component based on their needs.
To easily understand this, you can think of select
and option
HTML elements and how they work.
Let us modify the Button example above using Compound components.
export const ButtonRoot = (props) => {
return <button {...props}>{props.children}</button>
}
export const ButtonIcon = (props) => {
return <Icon {...props} />
}
export const ButtonText = (props) => {
return <span {...props}>{props.children}</span>
}
export const Button = {
Root: ButtonRoot,
Icon: ButtonIcon,
Text: ButtonText,
}
// It can then be used assuch
<Button.Root>
// Left Icon
<Button.Icon icon="plus" size={10} />
<Button.Text>Add More</Button.Text>
// Right Icon
<Button.Icon icon="plus" size={10} />
</Button.Root>
This approach provides a cleaner structure, is much more readable, maintainable and scalable.
You can learn more about this pattern here
Good luck! ππ»