Composition in React

Concept of Composition in React (Children Props) with Examples:

In this article, I am going to discuss the Concept of Composition in React (Children Props) with Examples. In our previous article, we have learned a lot about components. So, by now, we have got components everywhere. We have created ExpenseItem and ExpenseDate components. In our upcoming articles, we’ll learn about more features that we can add to these components to make them more interactive, improve their performance, send HTTP requests, and much more.

We learned about props that are used for configuring these components for passing data into them. And components are just custom HTML elements where you combine HTML code, JSX code, and styling. And if you want to, also extra JavaScript logic, as we have done this in ExpenseDate. That’s what components are about.

What is Composition in React?

We build these components to build a user interface and that’s what we’ve already been doing in our previous articles. Generally, this approach of building a user interface from smaller building blocks is called composition. Now there’s one specifically interesting aspect of composition that we haven’t seen yet.

What if, we wanted to create a component that actually serves as a shell around any kind of other content? For now, we have highly specific components i.e. ExpenseDate, ExpenseItem, and Expenses. The ExpenseDate component is about outputting a date. The ExpenseItem component is about outputting an expense item. And in your React application, you will always have a lot of these very specific components. All these components are also configured through props, through the date prop, the title prop, and the amount prop in the case of ExpenseItem. And that is fairly standard. You’ll have a lot of these components in your React applications.

Composition Concept in React using our Expense Tracker Project:

Sometimes, however, you want to have a component where you don’t configure everything through props but instead, you’re able to pass content between the opening and closing tags of that component.

Composition Concept in our Expense Tracker Project

And we have an example where this would make sense. If we have a look at our current output,

Composition Concept in React using our Expense Tracker Project

Here, we can see two kinds of boxes or containers. We got a container around all the expense items. It has a light grey background, rounded corners, and a slight drop shadow, which might be hard to see.

Composition Concept in React using our Expense Tracker Project

And we have a container around the list of the overall expenses, with a darker grey background, rounded corners, and a slight drop shadow.

Composition Concept in React using our Expense Tracker Project

Now, the idea behind all of these components is to have reusable building blocks and to avoid code duplication. And here, we have some style duplication, also some HTML structure duplication.

Concept of Composition in React (Children Props) with Examples

Here, we have a div that surrounds our expenses which applies certain styles. In ExpenseItem.js,

Concept of Composition in React (Children Props) with Examples

Here, not all divs have the same look though. Inside our expense items, we also got divs which have a different look. Nonetheless, we can extract the surrounding container div which we have both in ExpenseItem and Expenses.js. We can extract the styles that they have in common like rounded corners and a drop shadow into a separate component. And we can name such a component as a card because this is a specific card look. And this is not a term we came up with. Instead in general, in web development, when you hear the term ‘card’, it typically means some kind of container look with rounded corners, drop shadows, and elements like the above. So that’s why we’re picking the card as a name here.

Adding Card Layout Component in React:

Let’s create a Card.js file in our components folder. Now, such a card component is still a regular component here. But such a card component can do one main thing. It can return a div or any other kind of container i.e. HTML element with a class name card. And now we can add a Card.css file in the components folder and import that into our card component as,

Adding Card Layout Component

In the Card.css file, we can add the below code,

.card {
      border-radius: 12px;
      box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}

We have extracted the box-shadow and the border-radius from the Expenses.css file and added them inside the Card.css class selector. Maybe we can extract more styles but we will go with these two. So, we can delete the above code in the Expenses.css file.

Adding Card Layout Component in React

We will also go to ExpenseItem.css and there, in the ‘expense-item’ class selector, we have defined a box-shadow and a border-radius. So, we will remove these styles from there as well.

Adding Card Layout Component in React

Now, why we are doing that? Just to show the card component. Now we got this card container component which should act as a shell around either our ExpenseItem content or Expenses content. And that’s the key. Now, this card component will not be configured through some attributes. Instead, our idea would be that, let’s say in ExpenseItem,

Adding Card Layout Component in React

We can simply replace this above-highlighted built-in div with our custom card component. And then we get the predefined styles for the card automatically. We just want to make them extensible. For that, we have to import the Card inside of ExpenseItem.

Adding Card Layout Component in React

If we save it and see the output,

Adding Card Layout Component in React

We can see that all the expense items are lost. And the reason for that is we can’t use our custom components as wrappers around other kinds of content. Having content between opening and closing tags doesn’t work. But it will work for built-in HTML elements, like the div or the h2 tag. So, it would be nice if we could make it work for our custom components as well to build such reusable wrapper components. And of course, React has a solution here.

Build Custom Components as Wrappers Elements in React:

We can build such wrapper components in React. In Card.js, if we accept props.

function Card (props) {…}

It will not work with some attributes. But instead, we will use one special prop which is built into React, which every component receives, even if you’re never setting it explicitly. And that’s a prop which value we want to output between the opening and closing tag of the div, inside of the card component function.

Build Custom Components as Wrappers Elements in React

It’s props.children. Children is a reserved name.

Build Custom Components as Wrappers Elements in React

Here, we aren’t setting a children prop on this card. We’re setting a class name prop and actually, this won’t do anything. But we’re not setting a children prop. Children, as we said, is a reserved name and the value of this special children prop will always be the content between the opening and closing tags of your custom component. So in this case, the content between the opening and closing card tags,

Build Custom Components as Wrappers Elements in React

This is what will be available on props children inside of that card. And therefore, if we now save this,

Build Custom Components as Wrappers Elements in React

Here, we got some content back. However, it’s also a bit broken. And the reason for this is that we extracted some styles which ExpenseItem and Expenses had in common, but we had more styles to find for expense items. Those styles are important but they’re missing now. We have set the class name prop on the card but you must not forget that card is now a custom component defined by us. All the default HTML components support class names for adding CSS classes to the rendered HTML elements. But your custom components only support what you tell them to support.

So, if you want to make sure that a class name can be set on your card component and then has an effect, we have to tweak the code in the card component. We probably want to tweak it such that we add whatever is set as a class name on the card in ExpenseItem.js to the class name string in Card.js, we’re setting as a class name on the div in Card.js.

Build Custom Components as Wrappers Elements in React

So in Card.js, we can add a constant name ‘classes’ which is set to card as a default class which is always applied, white space plus props.className.

const classes = ‘card’ + props.className;

So, anything that we receive as a class name from outside will be added to the ‘classes’ string. And then we can dynamically point at classes constant.

Build Custom Components as Wrappers Elements in React

So with that, we’re now making sure that any value set on the prop.className is added to this string of class names which is then finally set on the div inside of the card. And with that all, if we saved it,

Concept of Composition in React with Examples

Now, we get the same look as before, not for the expenses (the outer card is not rounded), but for the expense items. Now we have this reusable wrapper component. And we can also use that in Expenses now. In Expenses.js, instead of using a div, we can use our card component.

Concept of Composition in React with Examples

Here, we are setting an extra class name ‘Expenses’. And if we save this,

Concept of Composition in React with Examples

Now we get the rounded corners back on the expenses container. A question may arise in your mind that why did we do this? What did we gain by doing that? Well, in this case, not a lot but we were able to extract some code duplication from inside our CSS files into this separate wrapper component. And it’s not just a duplicate CSS code we are also able to extract the JSX code, that div in Card.js.

In this case, it was just one div but throughout the course, you will see more complex wrapper components which might have a more complex JSX structure. Things like modals and alerts. And in such cases, we will be able to extract code which also allows us to save a lot of code duplication and it often allows you to keep your other components clean. This is another aspect of composition. We composed our ExpenseItem component by using the card as a wrapper, by using some built-in HTML elements, and by putting in the ExpenseDate. And all these components and elements are composed together to form the overall ExpenseItem component which can be used in other components. In the end, build the overall user interface.

Conclusion:

So, the composition is important. You will use it all the time when working with React. Whenever you combine components, you are using composition. And an especially important part of the composition is the props.children feature which allows you to also create wrapper components which is a special type of component. This is the thing which you also sometimes need.

Below is the code of all the files that we have used in this article,

Card.js:
import "./Card.css"

function Card(props) {
  const classes = 'card ' + props.className;
  return <div className={classes}>{props.children}</div>;
}

export default Card;
Card.css:
.card {
  border-radius: 12px;
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}
Expenses.js:
import ExpenseItem from "./ExpenseItem";
import "./Expenses.css";
import Card from "./Card";

function Expenses(props) {
  return (
    <Card className="expenses">
      <ExpenseItem
        title={props.items[0].title}
        amount={props.items[0].amount}
        date={props.items[0].date}
      />
      <ExpenseItem
        title={props.items[1].title}
        amount={props.items[1].amount}
        date={props.items[1].date}
      />
      <ExpenseItem
        title={props.items[2].title}
        amount={props.items[2].amount}
        date={props.items[2].date}
      />
    </Card>
  );
}

export default Expenses;
Expense.css:
.expenses {
    padding: 1rem;
    background-color: rgb(31, 31, 31);
    margin: 2rem auto;
    width: 50rem;
    max-width: 95%;
  }
ExpenseItem.js:
import ExpenseDate from "./ExpenseDate";
import Card from "./Card";
import "./ExpenseItem.css";

function ExpenseItem(props) {
  return (
    <Card className="expense-item">
      <ExpenseDate date={props.date}/>
      <div className="expense-item__description">
        <h2>{props.title}</h2>
        <div className="expense-item__price">₹{props.amount}</div>
      </div>
    </Card>
  );
}

export default ExpenseItem;
ExpenseItem.css:
.expense-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    padding: 0.5rem;
    margin: 1rem 0;
    border-radius: 12px;
    background-color: #696969;
  }
  
  .expense-item__description {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    align-items: flex-end;
    flex-flow: column-reverse;
    justify-content: flex-start;
    flex: 1;
  }
  
  .expense-item h2 {
    font-size: 1rem;
    flex: 1;
    margin: 0 1rem;
    color: white;
  }
  
  .expense-item__price {
    font-size: 1rem;
    font-weight: bold;
    color: white;
    background-color: #dd4a36;
    border: 1px solid white;
    padding: 0.5rem;
    border-radius: 12px;
  }
  
  @media (min-width: 580px) {
    .expense-item__description {
      flex-direction: row;
      align-items: center;
      justify-content: flex-start;
      flex: 1;
    }
  
    .expense-item__description h2 {
      font-size: 1.25rem;
    }
  
    .expense-item__price {
      font-size: 1.25rem;
      padding: 0.5rem 1.5rem;
    }
  }
App.js:
import Expenses from "./components/Expenses";

function App() {
  const expenses = [
    { title: "Household Expense", amount: 25000, date: new Date(2023, 4, 27) },
    { title: "Travel Expense", amount: 1300, date: new Date(2023, 5, 28) },
    { title: "Education fees", amount: 5000, date: new Date(2023, 6, 29) },
  ];

  return (
    <div>
      <h2>Hello Coders!</h2>
      <Expenses items={expenses}/>
    </div>
  )
}

export default App;

In the next article, I am going to discuss the Summary of React Component. Here, in this article, I try to explain the concept of Composition in React with Examples. I hope you enjoy this Concept of Composition in React with Examples article.

Leave a Reply

Your email address will not be published. Required fields are marked *