When writing user interfaces with the React framework, I often find that several of my components have similar behaviour. For example, I may have several components that display the eventual value of a promise, or display changing values of an Rx event stream, or are sources or targets for drag-and-drop interactions, and so on. I want to define these common behaviours once and compose them into my component classes where required. This, in a nutshell, is what “higher-order components” do.

An Example Use Case for Higher-Order Components

Imagine we’re writing an international e-commerce site.

When a customer uses the site, the information they see is localised for the country in which they reside. The site uses the user’s country to determine the currency in which to display prices, calculate shipping costs, etc. The site displays the customer’s country in the navigation bar at the top of each page. If the user is travelling, they can select their preferred country from a menu of countries supported by the site.

Both the country associated with the user’s session and the list of all countries supported by the application are fetched by HTTP from the server in JSON format and displayed by React components.

For example, the user’s country is served as:

{"iso": "gb", "name": "United Kingdom"}

And the list of supported countries is served as:

[ {"iso": "fr", "name": "France"}, {"iso": "gb", "name": "United Kingdom"}, ... ]

The Country component below displays the user’s preferred country. Because country data is received asynchronously, the Country component must be given a promise of the country information. While the promise is pending, the component displays a loading indicator. When the promise is resolved successfully, the component displays the country information as a flag icon and name. If the promise is rejected, the component displays an error message.

class Country extends React.Component { constructor(props) { super(props); this.state = {loading: true, error: null, country: null}; } componentDidMount() { this.props.promise.then( value => this.setState({loading: false, country: value}), error => this.setState({loading: false, error: error})); } render() { if (this.state.loading) { return <span>Loading...</span>; } else if (this.state.error !== null) { return <span>Error: {this.state.error.message}</span>; } else { var iso = this.state.country.iso; var name = this.state.country.name; return ( <span className="country"> <span className={"flag-icon flag-icon-"+iso}/> <span className="country-name">{name}</span> </span> ); } } }

It can be used like this (assuming fetchJson starts loading JSON from a URL and returns a promise of the JSON):

<Country promise={fetchJson('/api/country.json')}/>

The CountryChooser component below displays the list of available countries, which are also passed to it as a promise:

class CountryChooser extends React.Component { constructor(props) { super(props); this.state = {loading: true, error: null, countries: null}; } componentDidMount() { this.props.promise.then( value => this.setState({loading: false, countries: value}), error => this.setState({loading: false, error: error})); } render() { if (this.state.loading) { return <span>Loading...</span>; } else if (this.state.error !== null) { return <span>Error: {this.state.error.message}</span>; } else { return ( <ul className="country-chooser"> {this.state.countries.map(c => <li key={c.iso} onClick={() => this.props.onSelect(c.iso)}> <span className="country"> <span className={"flag-icon flag-icon-"+c.iso}/> <span className="country-name">{c.name}</span> </span> </li>) } </ul> ); } } }

It can be used like this (assuming the same fetchJson function and a changeUsersPreferredCountry function that sends the change of country to the server):

<CountryChooser promise={fetchJson('/api/countries.json')} onSelect={changeUsersPreferredCountry}/>

There’s a lot of duplication between the two components.

They duplicate the state machine required to receive and render data obtained asynchronously from a promise. These are not the only React components in the application that need to display data loaded asynchronously from the server, so addressing that duplication will shrink the code significantly.

The CountryChooser component cannot use the Country component to display the countries in the list because the event handling is intermingled with the presentation of the data. It therefore duplicates the code to render a country as HTML. We don’t want these HTML fragments diverging, because that will then create further duplication in our CSS stylesheets.

What can we do?

We can’t achieve what we want with parent/child relationships between components, where a parent component handles the promise events and child components render the promised value. Child component props are specified in the code that creates the component hierarchy, but at that point the we do not know the prop values. We want to calculate the props dynamically, when the promise is resolved.

We could extract the promise event handling into a base class. But JavaScript only supports single inheritance, so if our components inherit event handling for promises, they cannot inherit base classes that provide event handling for other things, such as user interaction . And although it disentangles the promise event handling from the rendering, it doesn’t disentangle the rendering from the promise event handling, so we still couldn’t use the Country component within the CountryChooser.

It sounds like a job for mixins, but React’s mixins don’t work with ES6 classes and are going to be dropped from the API.

The solution is a higher-order component.