Compound Component Pattern
common pattern
app.js
import Counter from "./Counter";
import "./styles.css";
export default function App() {
return (
<div>
<h1>Compound Component Pattern</h1>
<Counter
iconIncrease="+"
iconDecrease="-"
label="My NOT so flexible counter"
hideLabel={false}
hideIncrease={false}
hideDecrease={false}
/>
</div>
);
}
counter.js file
function Counter() {
return <span>Counter</span>;
}
export default Counter;
Compound Component Pattern
app.js
import Counter from "./Counter";
import "./styles.css";
export default function App() {
return (
<div>
<h1>Compound Component Pattern</h1>
<Counter>
<Counter.Label>My super flexible counter</Counter.Label>
<Counter.Decrease icon="-" />
<Counter.Increase icon="+" />
<Counter.Count />
</Counter>
<div>
<Counter>
<Counter.Decrease icon="◀️" />
<div>
<Counter.Count />
</div>
<Counter.Increase icon="▶️" />
</Counter>
</div>
</div>
);
}
counter.js
import { createContext, useContext, useState } from "react";
// 1. Create a context
const CounterContext = createContext();
// 2. Create parent component
function Counter({ children }) {
const [count, setCount] = useState(0);
const increase = () => setCount((c) => c + 1);
const decrease = () => setCount((c) => c - 1);
return (
<CounterContext.Provider value={{ count, increase, decrease }}>
<span>{children}</span>
</CounterContext.Provider>
);
}
// 3. Create child components to help implementing the common task
function Count() {
const { count } = useContext(CounterContext);
return <span>{count}</span>;
}
function Label({ children }) {
return <span>{children}</span>;
}
function Increase({ icon }) {
const { increase } = useContext(CounterContext);
return <button onClick={increase}>{icon}</button>;
}
function Decrease({ icon }) {
const { decrease } = useContext(CounterContext);
return <button onClick={decrease}>{icon}</button>;
}
// 4. Add child components as proeprties to parent component
Counter.Count = Count;
Counter.Label = Label;
Counter.Increase = Increase;
Counter.Decrease = Decrease;
export default Counter;