Conditional Rendering with Recompose

Mitch Masia
hexient-labs
Published in
3 min readMar 16, 2018

Let’s take on non-ideal states the functional way.

Non-Ideal State

If you’re a frequent user of web or mobile apps, you’ve probably seen an empty or error state on a page. Many times, this will come in the form of a list-view with no results. Handling these states with a cute animation has become commonplace and makes for a delightful user experience.

In one of our React Native apps at Hexient Labs, we handle the offline condition with a modal overlay:

Offline Modal with Lottie Animation

The modal above tells the user in a friendly way that something is wrong, and how to resolve it. So although the user has to take action, they aren’t too turned off.

These are the exact types of non-ideal states that UI designers and proficient developers have started implementing in their apps to provide a delightful user experience even under bad circumstances.

Recompose?

Recompose by Andrew Clark is an excellent “utility belt” of higher-order functions that allow developers to enhance the functionality of their components via composition.

One of the most simple examples of this is using the setPropTypes and defaultPropsHOCs to enhance a functional component with some prop-type requirements and default props.

import React from 'react'
import PropTypes from 'prop-types'
import { compose, defaultProps, setPropTypes } from 'recompose'
// Component
const Button = props => <button {...props}>{props.title}</button>
// Enhancers
const withPropTypes = setPropTypes({
onClick: PropTypes.func.isRequired,
title: PropTypes.string.isRequired,
})
const withDefaultProps = defaultProps({
onClick: () => {},
title: 'Submit',
})
export default compose(withDefaultProps, withPropTypes)(Button)

In the example above, the withPropTypes and withDefaultProps Higher-Order Components are composed together with the Button component to provide enhanced functionality without coupling them directly to the Button. In fact, these HOCs could be used in any component in our application!

So how can we use this same principle for conditional rendering??

Enter the “branch” HOC

The branch HOC is another utility function from Recompose that is commonly used with the renderComponent and renderNothing HOCs.

Here’s an example of rendering a List and a non-ideal state when it is empty:

// List.js
import React from 'react'
import PropTypes from 'prop-types'
import { branch, compose, defaultProps, renderComponent, setPropTypes } from 'recompose'
import EmptyState from '../components/common/EmptyState'
import Loader from '../components/common/Loader'
// Component
const List = props => (
<ul>
{props.data.map(item => <li key={item}>{item}</li>}
</ul>
)
// Enhancers
const withPropTypes = setPropTypes({
data: PropTypes.array.isRequired,
loading: PropTypes.bool.isRequired,
})
const withDefaultProps = defaultProps({
data: [],
loading: false,
})
const withLoadingState = branch(
props => props.loading,
renderComponent(Loader),
)
const withEmptyState = branch(
props => props.data.length === 0,
renderComponent(EmptyState),
)
export default compose(
defaultProps,
withLoadingState,
withEmptyState,
withPropTypes
)(List)

The example above composes our propTypes, defaultProps, loading state, and empty state together onto a single functional component List. The withLoadingState and withEmptyState can even be composed onto other components as well!

This is just one example of the power of Recompose- I’d highly recommend checking it out to encapsulate your rendering logic into functional pieces that are easily testable and composable.

--

--

Mitch Masia
hexient-labs

Mitch is a developer, teacher, and entrepreneur building cool things at Guaranteed Rate.