Compound Component Pattern
If you find yourself passing props through multiple layers of components, consider using the Compound Component Pattern.
The Compound Component Pattern is a powerful design pattern that is widely used in React applications. It can improve reusability, readability, and scalability.
This pattern builds a UI by combining multiple related child components under a shared parent component.
A familiar example is the element and its elements. These elements are designed to work together rather than independently. The element manages the selected value, while the elements represent the available choices.
Similarly, in the Compound Component Pattern, state is typically managed by the parent component and shared with its child components.
This pattern also establishes an implicit relationship between the parent and child components while still allowing consumers to customize the component structure.
Without the Compound Component Pattern
First, let’s implement a counter component without using the Compound Component Pattern.
You might notice that the component starts to become a little complicated because it has to manage the counter state, conditionally apply styles based on that state, and define the behavior of each UI element.
Counter.tsx
const Counter = () => {
const { count, handleDecrementClick, handleIncrementClick } = useCounter();
return (
<>
<p className="count">
Count: <span className={count <= 10 ? "red" : ""}>{count}</span>
</p>
<button className="minus-button" onClick={handleDecrementClick}>
-
</button>
<button className="plus-button" onClick={handleIncrementClick}>
+
</button>
</>
);
};
Using the Compound Component Pattern
Now, let’s implement the same component using the Compound Component Pattern.
You might notice that the component becomes much more declarative and easier to read.
Counter.tsx
const CounterExample = () => {
const handleChangeCounter = (count: number) => {
console.log("count", count);
};
return (
<Counter onChange={handleChangeCounter}>
<Counter.Label>
Count: <Counter.Count max={10} />
</Counter.Label>
<Counter.Increment>+</Counter.Increment>
<Counter.Decrement>-</Counter.Decrement>
</Counter>
);
};
With the Compound Component Pattern, each child component has a clear responsibility.
The parent component manages the shared state, while components such as , , and provide specific pieces of functionality.
As a result, users of the component can understand its structure directly from the JSX and can arrange the child components more flexibly without having to manage the internal state themselves.
Top comments (0)