React - March 3, 2024

Component Composition in React

5 minute read

I do not have to tell you that React is all about reusability. By creating components, we can reuse the same code to render identical pieces of HTML in different parts of our application. A very common use case of a component that needs to be rendered in different places of an application is an Alert component. Based on the context of the alert, it might need to be styled differently, have different text, or a different icon. Implementing such a component can be done in multiple ways. In this article, I will quickly discuss one "bad" implementation and show you how to improve it by using component composition.

Success!

You have successfully logged in.

Error!

Something went wrong.

A simple implementation (the bad way)

Let's look at the example Alerts above. If we deconstruct these alerts, we can see that they consist of a few parts: an icon, a title, a description, and a color (success or error).

If we were to implement this component, we could simply receive a set of props that would determine the content and styling of the alert. For example:

<Alert 
	type="success" 
	title="Success!" 	
	message="You have successfully logged in." 
	icon="info"
/>

Implementing the Alert component like this is perfectly valid React code.

But

, there are some improvements to be made. Let's ask ourselves the following questions:

  • What if we want to add a new type of icon?
  • What if we do not want to display an icon at all?
  • What if we want to add a link to the alert description?

Providing a solution to these questions is not that easy with the current implementation. In fact, it requires us to make all kind of adjustmenst inside the component itself. By refactoring our code to use component composition, we can solve these issues and make our code more compliant with the SOLID principles of programming. Let's quickly dive into the SOLID principles and see why our current implementation violates these principles.

1. Single Responsibility Principle

The Single Responsibility Principle (SRP) states that a class (or in this case, a component) should be responsible for only one thing. In the case of the Alert component, it is responsible for rendering the alert, but it is also responsible for determining the content and styling of the alert. This is not ideal, as it makes the component less flexible and harder to maintain.

2. Open/Closed Principle

The Open/Closed Principle states that a class (or again, in this case, a component) should be open for extension, but closed for modification. Looking at the implementation, it is very difficult to extend the component with new styling or content. For example, if we want to add a new type of icon, we would have to modify the Alert component itself.

Alright, so what is the solution?

Implementing Component Composition

Let's improve our component by using component composition. Component composition is a way of creating UI (HTML) by composing multiple smaller components together (often using the dot notation). In our case, we can create individual small components for the icon, title, and description, and then compose these components together to create the Alert component. This would look something like this:

<Alert type="success">
	<InformationCircleIcon />
	<Alert.Title>Component Composition!</Alert.Title>
	<Alert.Description>Now I'm super flexible.</Alert.Description>
</Alert>

Component Composition!

Now I'm super flexible.

Looking at the code above, we can see that we created two new individual small components that are rendered inside the Alert component (HOC):

  • Alert.Title
  • Alert.Description

By composing these components together with the Alert component, we can create a more flexible and maintainable alert! Each of these components is responsible for rendering a specific piece of the alert, which fully complies with the Single Responsibility Principle.

Another big advantage of this approach is that we can easily extend (or modify) the alert component. For example, if we want to use a different icon, we can simply replace the InformationCircleIcon with a CakeIcon. This means that we can now modify the alert without actually modifying the Alert component itself. This complies with the Open/Closed Principle.

<Alert type="success">
	<CakeIcon />
	<Alert.Title>New Icon!</Alert.Title>
	<Alert.Description>Who doesn't like cake?</Alert.Description>
</Alert>

New Icon!

Who doesn't like cake?

Lets look at another example. What if we want the description of the alert to contain a link and be displayed above the title. In this case we can simply add an anchor tag inside of the Alert.Description component and move it above the Alert.Title component.

<Alert type="success">
	<CakeIcon />
	<Alert.Description>
		I'm on top now with a <a href="#">link</a>
	</Alert.Description>
	<Alert.Title>New Icon!</Alert.Title>
</Alert>

I'm on top now with a link

New Icon!

The full implementation

You can find the full implementation of the Alert component using component composition below.

See the full implementation

Conclusion

By using component composition, it is very easy to create extenable and maintainable components in React. It allows us, developers, to reuse the same components in different parts of our application without having to modify the component itself. This not only makes our code complient with the SOLID principles, but also makes our code more flexible and maintainable.