Component Composition in React
Tags: react, javascript, beginners
Published: 2022-02-23 08:49:24

---
canonical_url: https://imkev.dev/component-composition
---

Cross-posted from https://imkev.dev/component-composition

One of the most misunderstood design patterns in a React application is the render props pattern and component composition. While this isn't a new or novel approach and has been promoted since at least 2017, five years later I still encounter opportunities where it should have been used instead of an inheritance hierarchy. _Component composition_ is the technique of combining different modular components to construct another component.

## Render Props

"But almost all components are made up of sub-components, so what's so special about component composition?" I hear you say. I distinguish between a regular component and component composition by passing one or more of the sub-components as props to the parent component. These props are known as _render props_ and the most commonly used render prop is the `children` prop which is included in React by default.

Let's take a look at an example.

```jsx
import Title from "./Title";

export default function MyComponent({ title, text }) {
  return (
    <div className="container">
      <Title title={title} />
      <p class="text">{text}</p>
    </div>
  );
}

export default function App() {
  return (
    <div className="app>>
      <MyComponent
        title="Random title #1"
        text="Lorem ipsum..."
      />
    </div>
  )
}
```

[Inheritance Demo](https://codesandbox.io/s/inheritance-j3s2s)

The component above might look fairly ordinary. A component `MyComponent` renders a `div` element and within it, there are two child elements. One being the `<Title>` component and the other being a `<p>` element. `MyComponent` receives two props, the `title` and the `text` component, which it outputs or passes onto the sub-component.

Let's see the same component using the component composition pattern.

```jsx
export default function MyComponent({ children }) {
  return <div className="container">{children}</div>;
}

export default function App() {
  return (
    <div className="app">
      <MyComponent>
        <>
          <Title title="Random title #1" />
          <p className="text">
            Lorem ipsum...
          </p>
        </>
      </MyComponent>
    </div>
  );
}
```

[Component Composition Demo](https://codesandbox.io/s/component-composition-jfo5l)

In this example, the role of `MyComponent` is reduced to creating a `div` element and placing the `children` prop within the `div`. The parent component which calls `MyComponent` is responsible for creating the `<Title>` and `<p>` elements. The generated HTML in these two examples is identical.

## Single-responsibility principle

When I was still at University studying computer science, amongst the many practices we were taught, there were the [SOLID principles](https://en.wikipedia.org/wiki/SOLID). Without going into the merits of the SOLID principles, the S in SOLID stands for the Single-Responsibility principle and states (paraphrasing) that a class or function should only have one reason to change. A class or function should only have one role. I like that. It makes it easier to understand, easier to debug, and makes your code more portable.

The component composition pattern helps enforce this practice as the role of `MyComponent` in the example above is to only create the `div` and place the `children` in the correct place. The role of `App` is to construct the composition of different components required to build the module. Contrary to the first example, `MyComponent` is not responsible for choosing the order of the `<Title>` and `<p>` elements, and if you would want to change their order, you would need to change `MyComponent`. This violates the Single-Responsibility principle.

## In practice

The above example is very simple and you are unlikely to encounter this scenario in a real-world environment. But the concept could be applied to any component structure.

In addition to displaying and outputting HTML, one of the more common tasks of a React component is to fetch data from a store or an API. Let's compare inheritance and component composition using an example where we are fetching a list of users and then displaying these in a `<ul>`.

```jsx
export default function UserList({ quantity }) {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch(`${API_URL}${quantity}`).then(async (response) => {
      if (response.ok) {
        const { results } = await response.json();
        setUsers(results);
      }
    });
  }, [quantity]);

  return (
    <div className="container">
      {users && Boolean(users.length) && (
        <ul className="list">
          {users.map((n) => (
            <li key={n.login.username} className="item">
              <UserCard
                username={n.login.username}
                city={n.location.city}
                profilePicture={n.picture.thumbnail}
              />
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default function App() {
  return (
    <div className="app">
      <UserList quantity={3} />
    </div>
  );
}
```

[Inheritance Data Demo](https://codesandbox.io/s/inheritance-data-mim6kn)

The `UserList` component receives a `quantity` prop indicating the number of items to retrieve from the API. Once the component is mounted, it will make a request, populate the result in the state, and then display a list of `UserCard` sub-components inside a `<ul>`.

Let's take a look at the same application if it were following the component composition pattern.

```jsx
export default function Users({ quantity, children }) {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch(`${API_URL}${quantity}`).then(async (response) => {
      if (response.ok) {
        const { results } = await response.json();
        setUsers(results);
      }
    });
  }, [quantity]);

  return children({ users });
}

export default function App() {
  return (
    <div className="app">
      <Users quantity={3}>
        {({ users }) => (
          <div className="container">
            {users && Boolean(users.length) && (
              <ul className="list">
                {users.map((n) => (
                  <li key={n.login.username} className="item">
                    <UserCard
                      username={n.login.username}
                      city={n.location.city}
                      profilePicture={n.picture.thumbnail}
                    />
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}
      </Users>
    </div>
  );
}
```

[Component Composition Data Demo](https://codesandbox.io/s/component-composition-data-fxs4b7)

The `App` component now renders a `Users` component. This component is solely responsible for fetching the users from the API and returning them as a prop to the `children` using the return statement `return children({ users })`. Any child component of `Users` will have access to the `users` as a prop. The `App` component iterates through the users it receives and creates the `<ul>`.

The latter approach allows you to separate fetching data from displaying it. If a change request comes in that requires the data to be filtered before being displayed, you immediately know that you do not need to do any changes to the `Users` component as the change request does not require changes to the fetching of data. [Demo](https://codesandbox.io/s/component-composition-grid-gs04o7)

## Multiple Render Props

While in many cases you can use the `children` prop included in React, in some cases you may need to place multiple sub-components that will not be rendered beside each other in the DOM. In these cases, you may define further _render props_ similarly to how you would assign an ordinary prop. The only difference is that you pass a component.

```jsx
export default function MyComponent({ headerFn, children }) {
  return (
    <>
      <div className="header">{headerFn}</div>
      <hr />
      <div className="container">{children}</div>
    </>
  );
}

export default function App() {
  return (
    <div className="app">
      <h1>Component Composition</h1>
      <MyComponent headerFn={<Title title="Random title #1" />}>
        <p className="text">
          Lorem ipsum...
        </p>
      </MyComponent>
    </div>
  );
}
```

In this simple example, we have added `headerFn` prop to `MyComponent` and passed `<Title title="Random title #1" />` to it. `MyComponent` is only responsible for the DOM structure and placing the correct CSS classes, while `App` is responsible for defining the components to be rendered.

## Conclusion

The component composition pattern can simplify your applications, making the code more portable, maintainable, and [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). Once you become accustomed to this pattern, it is easy to apply it in almost any situation you would have previously used inheritance.

I hope this helped convince you to make use of component composition more often. If you're not yet convinced, ReactJS docs go as far as to say that they [haven’t found any use cases where they would recommend creating component inheritance hierarchies](https://reactjs.org/docs/composition-vs-inheritance.html#so-what-about-inheritance) and [Michael Jackson](https://twitter.com/mjackson) has a fantastic video (one of many) on this topic [Never Write Another HoC](https://www.youtube.com/watch?v=BcVAq3YFiuc).

Thank you for reading. Have a good one! 👋

Image credits: Photo by [Ricardo Gomez Angel](https://unsplash.com/@rgaleria?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)