React Concept: Composition
By Flavio Copes
Learn why composition is a key concept in React: build small, focused components, then combine them by specializing them and passing methods as props.
Composition in React means building complex UI by combining small, focused components. Instead of one giant component that does everything, you write pieces that each do one thing, and assemble them.
In programming, composition allows you to build more complex functionality by combining small and focused functions.
For example, think about using map() to create a new array from an initial set, and then filtering the result using filter():
const list = ['Apple', 'Orange', 'Egg']
list.map(item => item[0]).filter(item => item === 'A') //['A']
Neither function knows about the other. Each does its job, and you chain them.
In React, the same idea gives you some pretty cool advantages. It’s also the approach the React team recommends over class inheritance: you’ll almost never extend a component, you compose it.
You create small and lean components and use them to compose more functionality on top of them. How? Here are the main patterns.
Create specialized versions of a component
Use an outer component to expand and specialize a more generic component:
const Button = props => {
return <button>{props.text}</button>
}
const SubmitButton = () => {
return <Button text="Submit" />
}
const LoginButton = () => {
return <Button text="Login" />
}
Button handles the generic case. SubmitButton and LoginButton just fix one prop. When you later add styling or accessibility fixes to Button, every specialized version gets them for free.
Pass methods as props
A component can focus on tracking a click event, for example, and what actually happens when the click event happens is up to the container component:
const Button = props => {
return <button onClick={props.onClickHandler}>{props.text}</button>
}
const LoginButton = props => {
return <Button text="Login" onClickHandler={props.onClickHandler} />
}
const Container = () => {
const onClickHandler = () => {
alert('clicked')
}
return <LoginButton onClickHandler={onClickHandler} />
}
Button stays reusable because it doesn’t decide what a click means. The decision lives in Container, the component that has the context to make it.
Using children
The props.children property allows you to inject components inside other components.
The component needs to output props.children in its JSX:
const Sidebar = props => {
return <aside>{props.children}</aside>
}
and you embed more components into it in a transparent way:
<Sidebar>
<Link title="First link" />
<Link title="Second link" />
</Sidebar>
Be careful with one thing here: if you forget to render {props.children} inside Sidebar, the nested components silently disappear. No error, no warning, just an empty aside. When content you nested doesn’t show up, check the wrapper renders its children.
Higher order components
When a component receives a component as a prop and returns a component, it’s called higher order component.
You can learn more about higher order components on my article React Higher Order Components.
Related posts about react: