DEV Community

Cover image for Component Composition In React - Basics.
Barnabas Babatunde
Barnabas Babatunde

Posted on

Component Composition In React - Basics.

Introduction:

In this article, we will go over component composition in React. Composition allows the reuse of code between React components.

Use Cases For Composition:

Two common use cases for composition are:

  1. Component specialization
  2. Component containment

1. Component Specialization:

Some React components may be special cases of some other React component. In this case, the more specific React component renders the more generic component, and then customizes it to fit into its own special purpose, using props.

Illustration:

Our code illustration will be a simple case: an e-commerce website which allows customers to create user accounts, and be able to make online item purchases.

When a user logs into the website, they can view a page showing purchases for 3 selected months - January, February, March.


First, we will create a generic component called MonthlyPurchases

import React from 'react'

const MonthlyPurchases = (props)=>{
    const {
        month,
        week1,
        week2,
        week3,
        week4
    } = props;


    return (
        <div>
            <h1>Month: {month}</h1>
            <h2>Total Purchase Per Week:</h2>
            <ul>
                <li>Week 1: {week1}</li>
                <li>Week 2: {week2}</li>
                <li>Week 3: {week3}</li>
                <li>Week 4: {week4}</li>
            </ul>
        </div>
    );
}


export default MonthlyPurchases;
Enter fullscreen mode Exit fullscreen mode

MonthlyPurchases will be rendered by the more specific January, February, and March components. Each specific component will customize MonthlyPurchase by passing props(containing specific data) to it.


Next, we will then go ahead to create our specific components:


January.js:

import React from 'react'
import MonthlyPurchases from './MonthlyPurchases';

const January = ()=>{
    return(
        <div>
            <MonthlyPurchases 
            month="January"
            week1="$100"
            week2="$150"
            week3="$110"
            week4="$135" />
        </div>
    );
}

export default January;
Enter fullscreen mode Exit fullscreen mode



February.js:

import React from 'react'
import MonthlyPurchases from './MonthlyPurchases';

const February = ()=>{
    return(
        <div>
            <MonthlyPurchases 
            month="February"
            week1="$50"
            week2="$80"
            week3="$190"
            week4="$75" />
        </div>
    );
}

export default February;
Enter fullscreen mode Exit fullscreen mode



March.js:

import React from 'react'
import MonthlyPurchases from './MonthlyPurchases';

const March = ()=>{
    return(
        <div>
            <MonthlyPurchases 
            month="March"
            week1="$200"
            week2="$180"
            week3="$390"
            week4="$175" />
        </div>
    );
}

export default March;
Enter fullscreen mode Exit fullscreen mode



Each specific component passes its own pertinent data (via props) to the generic MonthlyPurchases component. In doing so, we have been able to reuse the source code in MonthlyPurchases.js. This is an extremely simple illustration. The benefits of code reuse through composition becomes more obvious in much larger applications.

In App.js, we now mount all three specific components:

import React from 'react';
import February from './February';
import January from './January';
import March from './March';


const App = ()=>{

  return (
    <div className="App">
      <January />
      <February />
      <March />
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

We get the following output in our browser:
output in browser

2. Component Containment:

We can employ component composition in cases where a component does not 'know' its children components beforetime. An example of such case is a website's sidebar. A sidebar may not necessarily know (ahead of time) how many items it would contain at some point in the web application.
In this case, we use the special children prop to pass children (plain jsx or even other components) to the rendered output.

Illustration:

Our code illustration will also be a simple case: an e-commerce website which has a sidebar rendered in two locations on a page: left side and right side

The left sidebar displays all the items currently up for sale.
The right sidebar displays only the items with high discounts.



So, we go ahead and create a Sidebar components:

import React from 'react'

const Sidebar = (props)=>{
    return (
        <div>
            {
                props.children
            }
        </div>
    )
}

export default Sidebar;
Enter fullscreen mode Exit fullscreen mode



Next, we implement LeftSidebar and RightSidebar components, which will call Sidebar and pass in plain jsx as children to it. As seen from the source code of Sidebar, it accesses the jsx passed to it through props.children, and renders it in its own output.

LeftSidebar:

import React from 'react'
import Sidebar from './Sidebar'


const LeftSidebar = ()=>{
    return (
        <Sidebar>
            <h1>All available Items</h1>
            <ul>
                <li>Laptops</li>
                <li>Head phones</li>
                <li>Office chairs</li>
                <li>Card holders</li>
                <li>Table fans</li>
                <li>Television sets</li>
                <li>Lamps</li>
                <li>Cameras</li>
                <li>Mobile phones</li>
                <li>Power inverters</li>
                <li>Shoes</li>
                <li>Electric Iron</li>
                <li>Face masks</li>
                <li>Lamp holders</li>
            </ul>
        </Sidebar>
    )
}

export default LeftSidebar;
Enter fullscreen mode Exit fullscreen mode



RightSidebar:

import React from 'react'
import Sidebar from './Sidebar'


const RightSidebar = ()=>{
    return (
        <Sidebar>
            <h1>High Discount Items</h1>
            <ul>
                <li>Laptops</li>
                <li>Office chairs</li>
                <li>Table fans</li>
                <li>Lamps</li>
                <li>Mobile phones</li>
                <li>Shoes</li>
                <li>Face masks</li>
            </ul>
        </Sidebar>
    )
}

export default RightSidebar
Enter fullscreen mode Exit fullscreen mode



Finally, we then mount LeftSidebar and RightSidebar in App.js:

import './App.css';
import React from 'react';
import RightSidebar from './RightSidebar';
import LeftSidebar from './LeftSidebar';


const App = ()=>{

  return (
    <div className="App">
      <LeftSidebar />
      <RightSidebar />
    </div>
  )
}

export default App;
Enter fullscreen mode Exit fullscreen mode



We get the following output in our browser:
output in browser

Some final thoughts:

React's composition model is a very powerful (and interesting) one. And it is advisable to use composition instead of inheritance. There are also cases where composition proves better than the context API for passing data down the React component tree.

Conclusion:

In the last few minutes, we've had a look at component composition in React, and its application to component containment and component specialization. Hopefully, you can add this to your toolbox. Love and light folks!

Discussion (0)