Connected Higher Order components with React and Redux

Avi Zurel
Avi Zurel
Aug 5, 2016 · 3 min read

Recently I’ve started using React and Redux to rebuild one of the major components on the Gogobot website.

In order to understand the problem better, here are some screenshots of one of the components on that page.

Image for post
Image for post
Filter component on the Gogobot map

Without really understanding the ins and outs of the component, you can see that the components share many things:

  1. Count label that is shown/hidden based on the number of items I selected from the filter.
  2. Drop down that opens on click of the icon.
  3. Once clicked, it sends an event (action) and requests the data from the
  4. Once clicked, it sends an event (action) and requests the data from the server based on the new filter.

Sitting down to design this component I realized that the **behavior** shared between each of them calls for a **higher order component** that will define the behavior and wrap all “child” components.

Doing this with pure React is fairly obvious so I’m not gonna go into that, this post is gonna be about doing this with Redux since the higher-order-component is connected to the dispatch, store and state.

Implementation

// src/components/Filters/FilterWrapper/index.jsimport React, { Component } from ‘react’;
import { bindActionCreators } from ‘redux’;
import { connect } from ‘react-redux’;
function FilterWrapper(ComposedFilter, filterInfo) {
class BaseFilter extends Component {
constructor() {
super();
this.state = {
count: 0
};
this.onCheckboxChange = this.onCheckboxChange.bind(this);
}
onClick(e) {

}
onCheckboxChange(e) {

}
render() {
let countLabel = this.state.count > 0 ?
<span>{ this.state.count }</span> :
null;
return(
<div className=”filterDetailsWrapper”>
<div className=”filterTotalCount”>
{ countLabel }
</div>
<div className=”optionsDropDownContainer”>
<ComposedFilter
{…this.state}
{…this.props}
onCheckboxChange={ this.onCheckboxChange }
/>
</div>
</div>
);
}
}
function mapStateToProps(state) {
// REDACTED
return {};
}
function mapDispatchToProps(dispatch) {
return {
…bindActionCreators(actions, dispatch)
};
}
return connect(mapStateToProps, mapDispatchToProps)(BaseFilter);
}
export default FilterWrapper;

Lets explain what’s going on here…

We’re creating a function that wraps a component and defines some behavior. This is shared behavior to all the wrapped components. In this example we only have the count label for the sake of example but you can obviously extend it to whatever you can.

Let’s take a look at the wrapped component (HotelClass) for this example

// src/components/Filters/HotelClass/index.jsimport React, { Component } from ‘react’;
import ReactDOM from ‘react-dom’;
import BaseFilterWrapper from ‘../BaseFilterWrapper’;
class HotelClass extends Component {
render() {
return(
<div className=”hotelClassOptions”>
<ul>
<li className=”optionsdropdown”>
<label className=”optionTitle”>5</label>
<input onChange={ this.props.onCheckboxChange } type=”checkbox” value=”5" />
</li>
<li className=”optionsdropdown”>
<label className=”optionTitle”>4</label>
<input onChange={ this.props.onCheckboxChange } type=”checkbox” value=”4" />
</li>
</ul>
</div>
)
}
}
let filterInfo = {
name: ‘hotel_class’,
class_name: ‘hotelClass’,
title: ‘Hotel Class’
};
export default BaseFilterWrapper(HotelClass, filterInfo);

As you can see, when the checkbox changes, it’s calling this.props.onCheckboxChange which is coming from the higher order component and in turn will call the behavior there.

The final lines are the “magic” ones, I pass some `filterInfo` which you can use any way you see fit (or not), and I pass the `HotelClass` component wrapped in `BaseFilterWrapper` function.

Now, lets implement the logic to show the count label when we click the checkboxes and hide it if the count is 0

onCheckboxChange(e) {
let { count } = this.state;
var { checked, value } = e.target;

if (checked) {
count += 1;
} else {
count -= 1;
}

this.setState({
count
});
}

That’s about it.

Now, you can share similar component logic.

Benefits

The clear benefits of this approach is that if you have a share behavior for a set of components, you only connect the “base” to the store and you manage everything from it. The rest of your components are just “dumb components” and the get injected with the behavior.

The code is much cleaner and there’s a single point of entry for actions/state changes to the system, this simplifies debugging and testing a lot and overall makes the code more readable.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store