---
title: "Using Recompose to build higher-order components"
description:
  "By the end of this blog you’ll learn how to use Recompose and improve the
  readability of your code."
canonical_url: "https://www.bigbinary.com/blog/using-recompose-to-build-higher-order-components"
markdown_url: "https://www.bigbinary.com/blog/using-recompose-to-build-higher-order-components.md"
---

# Using Recompose to build higher-order components

By the end of this blog you’ll learn how to use Recompose and improve the
readability of your code.

- Author: Arbaaz
- Published: September 12, 2017
- Categories: ReactJS

[Recompose](https://github.com/acdlite/recompose) is a toolkit for writing React
components using higher-order components. Recompose allows us to write many
smaller higher-order components and then we compose all those components
together to get the desired component. It improves both readability and the
maintainability of the code.

[HigherOrderComponents](https://facebook.github.io/react/docs/higher-order-components.html)
are also written as `HOC`. Going forward we will use `HOC` to refer to
higher-order components.

## Using Recompose in an e-commerce application

We are working on an e-commerce application and we need to build payment page.
Here are the modes of payment.

- Online
- Cash on delivery
- Swipe on delivery

We need to render our React components depending upon the payment mode selected
by the user. Typically we render components based on some state.

Here is the traditional way of writing code.

```javascript
state = {
  showPayOnlineScreen: true,
  showCashOnDeliveryScreen: false,
  showSwipeOnDeliveryScreen: false,
}

renderMainScreen = () => {
  const { showCashOnDeliveryScreen, showSwipeOnDeliveryScreen } = this.state;

  if (showCashOnDeliveryScreen) {
    return <CashOnDeliveryScreen />;
  } else if (showSwipeOnDeliveryScreen) {
    return <SwipeOnDeliveryScreen />;
  }
  return <PayOnlineScreen />;
}

 render() {
  return (
    { this.renderMainScreen() }
  );
 }

```

We will try to refactor the code using the tools provided by _Recompose_.

In general, the guiding principle of functional programming is composition. So
here we will assume that the default payment mechanism is _online_. If the
payment mode happens to be something else then we will take care of it by
enhancing the existing component.

So to start with our code would look like this.

```javascript
state = {
  paymentType: online,
}

render() {
  return (
    <PayOnline {...this.state} />
  );
}
```

First let's handle the case of payment mode _CashOnDelivery_.

```javascript
import { branch, renderComponent, renderNothing } from 'recompose';
import CashScreen from 'components/payments/cashScreen';

const cashOnDelivery = 'CASH_ON_DELIVERY';

const enhance = branch(
  (props) => (props.paymentType === cashOnDelivery)
  renderComponent(CashScreen),
  renderNothing
)
```

Recompose has
[branch](https://github.com/acdlite/recompose/blob/master/docs/API.md#branch)
function which acts like a ternary operator.

The `branch` function accepts three arguments and returns a `HOC`. The first
argument is a
[predicate](<https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)>)
which accepts props as the argument and returns a _Boolean_ value. The second
and third arguments are higher-order components. If the predicate evaluates to
**true** then the **left HOC** is rendered otherwise the **right HOC** is
rendered. Here is how `branch` is implemented.

```javascript
branch(
  test: (props: Object) => boolean,
  left: HigherOrderComponent,
  right: ?HigherOrderComponent
): HigherOrderComponent
```

Notice the question mark in `?HigherOrderComponent`. It means that the third
argument is optional.

If you are familiar with [Ramda](http://ramdajs.com) then this is similar to
[ifElse](http://ramdajs.com/docs/#ifElse) in Ramda.

[renderComponent](https://github.com/acdlite/recompose/blob/master/docs/API.md#rendercomponent)
takes a component and returns an HOC version of it.

[renderNothing](https://github.com/acdlite/recompose/blob/master/docs/API.md#rendernothing)
is an HOC which will always render `null`.

Since the third argument to `branch` is optional, we do not need to supply it.
If we don't supply the third argument then that means the original component
will be rendered.

So now we can make our code shorter by removing usage of `renderNothing`.

```javascript
const enhance = branch(
  (props) => (props.paymentType === cashOnDelivery)
  renderComponent(CashScreen)
)

const MainScreen = enhance(PayOnlineScreen);
```

### Next condition is handling SwipeOnDelivery

SwipeOnDelivery means that upon delivery customer pays using credit card using
[Square](https://squareup.com) or a similar tool.

We will follow the same pattern and the code might look like this.

```javascript
import { branch, renderComponent } from 'recompose';
import CashScreen from 'components/payments/CashScreen';
import PayOnlineScreen from 'components/payments/PayOnlineScreen';
import CardScreen from 'components/payments/CardScreen';

const cashOnDelivery = 'CASH_ON_DELIVERY';
const swipeOnDelivery = 'SWIPE_ON_DELIVERY';

let enhance = branch(
  (props) => (props.paymentType === cashOnDelivery)
  renderComponent(CashScreen),
)

enhance = branch(
  (props) => (props.paymentType === swipeOnDelivery)
  renderComponent(CardScreen),
)(enhance)

const MainScreen = enhance(PayOnlineScreen);
```

### Extracting out predicates

Let's extract predicates into their own functions.

```javascript
import { branch, renderComponent } from "recompose";
import CashScreen from "components/payments/CashScreen";
import PayOnlineScreen from "components/payments/PayOnlineScreen";
import CardScreen from "components/payments/CardScreen";

const cashOnDelivery = "CASH_ON_DELIVERY";
const swipeOnDelivery = "SWIPE_ON_DELIVERY";

// predicates
const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;

const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

let enhance = branch(isCashOnDelivery, renderComponent(CashScreen));

enhance = branch(isSwipeOnDelivery, renderComponent(CardScreen))(enhance);

const MainScreen = enhance(PayOnlineScreen);
```

### Adding one more payment method

Let's say that next we need to add support for
[Bitcoin](https://bitcoin.org/en).

We can use the same process.

```javascript
const cashOnDelivery = "CASH_ON_DELIVERY";
const swipeOnDelivery = "SWIPE_ON_DELIVERY";
const bitcoinOnDelivery = "BITCOIN_ON_DELIVERY";

const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;

const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

const isBitcoinOnDelivery = ({ paymentType }) =>
  paymentType === bitcoinOnDelivery;

let enhance = branch(isCashOnDelivery, renderComponent(CashScreen));

enhance = branch(isSwipeOnDelivery, renderComponent(CardScreen))(enhance);

enhance = branch(isBitcoinOnDelivery, renderComponent(BitcoinScreen))(enhance);

const MainScreen = enhance(PayOnlineScreen);
```

You can see the pattern and it is getting repetitive and boring. We can chain
these conditions together to make it less repetitive.

Let's use the
[compose](https://github.com/acdlite/recompose/blob/master/docs/API.md#compose)
function and chain them.

```javascript
const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;

const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

const cashOnDeliveryCondition = branch(
  isCashOnDelivery,
  renderComponent(CashScreen)
);

const swipeOnDeliveryCondition = branch(
  isSwipeOnDelivery,
  renderComponent(CardScreen)
);

const enhance = compose(cashOnDeliveryCondition, swipeOnDeliveryCondition);

const MainScreen = enhance(PayOnlineScreen);
```

### Refactoring code to remove repetition

At this time we are building a condition (like _cashOnDeliveryCondition_) for
each payment type and then using that condition in `compose`. We can put all
such conditions in an array and then we can use that array in `compose`. Let's
see it in action.

```javascript
const cashOnDelivery = "CASH_ON_DELIVERY";
const swipeOnDelivery = "SWIPE_ON_DELIVERY";

const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;

const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

const states = [
  {
    when: isCashOnDelivery,
    then: CashOnDeliveryScreen,
  },
  {
    when: isSwipeOnDelivery,
    then: SwipeOnDeliveryScreen,
  },
];

const componentsArray = states.map(({ when, then }) =>
  branch(when, renderComponent(then))
);

const enhance = compose(...componentsArray);

const MainScreen = enhance(PayOnlineScreen);
```

### Extract function for reusability

We are going to extract some code in `utils` for better reusability.

```javascript
// utils/composeStates.js

import { branch, renderComponent, compose } from "recompose";

export default function composeStates(states) {
  const componentsArray = states.map(({ when, then }) =>
    branch(when, renderComponent(then))
  );

  return compose(...componentsArray);
}
```

Now our main code looks like this.

```javascript
import composeStates from "utils/composeStates.js";

const cashOnDelivery = "CASH_ON_DELIVERY";
const swipeOnDelivery = "SWIPE_ON_DELIVERY";

const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;

const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

const states = [
  {
    when: isCashOnDelivery,
    then: CashScreen,
  },
  {
    when: isSwipeOnDelivery,
    then: CardScreen,
  },
];

const enhance = composeStates(states);

const MainScreen = enhance(PayOnlineScreen);
```

### Full before and after comparison

Here is before code.

```javascript
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { browserHistory } from "react-router";
import { Modal } from "react-bootstrap";
import * as authActions from "redux/modules/auth";
import PaymentsModalBase from "../../components/PaymentsModal/PaymentsModalBase";
import PayOnlineScreen from "../../components/PaymentsModal/PayOnlineScreen";
import CashScreen from "../../components/PaymentsModal/CashScreen";
import CardScreen from "../../components/PaymentsModal/CardScreen";

@connect(() => ({}), { ...authActions })
export default class PaymentsModal extends Component {
  static propTypes = {
    show: PropTypes.bool.isRequired,
    hideModal: PropTypes.func.isRequired,
    orderDetails: PropTypes.object.isRequired,
  };

  static defaultProps = {
    show: true,
    hideModal: () => {
      browserHistory.push("/");
    },
    orderDetails: {},
  };

  state = {
    showOnlineScreen: true,
    showCashScreen: false,
    showCardScreen: false,
  };

  renderScreens = () => {
    const { showCashScreen, showCardScreen } = this.state;

    if (showCashScreen) {
      return <CashScreen />;
    } else if (showCardScreen) {
      return <CardScreen />;
    }
    return <PayOnlineScreen />;
  };

  render() {
    const { show, hideModal, orderDetails } = this.props;
    return (
      <Modal show={show} onHide={hideModal} dialogClassName="modal-payments">
        <PaymentsModalBase orderDetails={orderDetails} onHide={hideModal}>
          {this.renderScreens()}
        </PaymentsModalBase>
      </Modal>
    );
  }
}
```

Here is after applying recompose code.

```javascript
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Modal } from "react-bootstrap";
import { compose, branch, renderComponent } from "recompose";
import * as authActions from "redux/modules/auth";
import PaymentsModalBase from "components/PaymentsModal/PaymentsModalBase";
import PayOnlineScreen from "components/PaymentsModal/PayOnlineScreen";
import CashOnDeliveryScreen from "components/PaymentsModal/CashScreen";
import SwipeOnDeliveryScreen from "components/PaymentsModal/CardScreen";

const cashOnDelivery = "CASH_ON_DELIVERY";
const swipeOnDelivery = "SWIPE_ON_DELIVERY";
const online = "ONLINE";

const isCashOnDelivery = ({ paymentType }) => paymentType === cashOnDelivery;
const isSwipeOnDelivery = ({ paymentType }) => paymentType === swipeOnDelivery;

const conditionalRender = states =>
  compose(
    ...states.map(state => branch(state.when, renderComponent(state.then)))
  );

const enhance = compose(
  conditionalRender([
    { when: isCashOnDelivery, then: CashOnDeliveryScreen },
    { when: isSwipeOnDelivery, then: SwipeOnDeliveryScreen },
  ])
);

const PayOnline = enhance(PayOnlineScreen);

@connect(() => ({}), { ...authActions })
export default class PaymentsModal extends Component {
  static propTypes = {
    isModalVisible: PropTypes.bool.isRequired,
    hidePaymentModal: PropTypes.func.isRequired,
    orderDetails: PropTypes.object.isRequired,
  };

  state = {
    paymentType: online,
  };

  render() {
    const { isModalVisible, hidePaymentModal, orderDetails } = this.props;
    return (
      <Modal
        show={isModalVisible}
        onHide={hidePaymentModal}
        dialogClassName="modal-payments"
      >
        <PaymentsModalBase
          orderDetails={orderDetails}
          hidePaymentModal={hidePaymentModal}
        >
          <PayOnline {...this.state} />
        </PaymentsModalBase>
      </Modal>
    );
  }
}
```

### Functional code is a win

Functional code is all about composing smaller functions together like lego
pieces. It results in better code because functions are usually smaller in size
and do only one thing.

In coming weeks we will see more applications of recompose in the real world.

## Links

- [Human page](https://www.bigbinary.com/blog/using-recompose-to-build-higher-order-components)
