What is composition
Let me demonstrate with a small example:
// no composition
<AlertDialog
open={true}
title="Don't use composition!"
/>
// with composition
<Dialog open={true}>
<Title>Don't use composition!</Title>
<Button>Close</Button>
</Dialog>
At first glance the first example seems like a good idea right? It's shorter and you've completely hidden that button component inside the AlertDialog
, so you dont have to worry about it anymore!
But now, we need another special alert dialog that can have an svg icon in the title! This means we have to change the interface of AlertDialog
so the title can take either a string
or a ReactNode
.
// no composition
<AlertDialog
open={true}
title={<><SvgAlertIcon /> Don't use composition!</>}
/>
// with composition
<Dialog open={true}>
<Title><SvgAlertIcon /> Don't use composition!</Title>
<Button>Close</Button>
</Dialog>
Or even worse, now the client also wants a special alert dialog (a confirmation dialog) that has a "cancel" and an "ok" button. This means we have to extensively modify the code inside AlertDialog
and we need to put conditional logic there, so it can either render a "close" button or a "cancel" and "ok" button.
// no composition
<AlertDialog
open={true}
title="Are you sure you don't want to use composition?"
asConfirmationDialog
/>
// with composition
<Dialog open={true}>
<Title>Are you sure you don't want to use composition?</Title>
<Button>Cancel</Button>
<Button>Ok</Button>
</Dialog>
You can imagine, the code inside AlertDialog
will get more complicated over time as requests for more features are made, meanwhile in the composition, NONE of the components have changed internally.
Why is composition important
From the above example, you can already see that composition is important because without it, the complexity of our components will grow exponentially over-time until they're no longer maintenable. But not using composition in React also violates some well known principles that you may remember from object oriented programming (the SOLID principles).
Single responsiblity
Sticking with the example of the alert dialog. We can see that the single responsibility principle is being violated. You expect the component to only be responsible for showing an alert dialog, but now it also contains logic to render a title and logic to show different buttons based on the asConfirmationDialog
flag.
Open/closed principle
The violation of the open/closed principle can also be applied to React components. We need to make modifications to the internal logic of AlertDialog
component if we want to extend it (it should be closed for modification and open for extension).
PS: When you are making a library of reusable components, not using composition means you just decided that developers using your library cannot (easily) make confirmation dialogs with your library. In practice that will mean you get a lot of feature requests or requests to change the interface of the components in your library. Or worse, developers will decide to use another library that uses composition.
Top comments (2)
Simple yet very effective article to demonstrate composition. I would encourage you to write more such articles, perhaps one that describes some rules to shape our logic on how to break things into components that follow composition and are maintainable. I sometimes feel that its quite unpopular and pretty hard to recognize for most React developers out there to identify when their React code is breaking rules and actually not taking full advantage of React by poorly adopting composition. Cheers!
Thanks for encouraging me to write more about this! I will have a go at it soon! How we break up our components is often a very opinionated thing though. I will have to approach that topic carefully! 😁