Reduce Your Boilerplate Code for Redux Container using React HOC

Higher Order Component (HOC) is one of advanced technique in React for reusing component logic to solve the cross-cutting concerns, e.g. role based authorization. We can also use this concept to reduce our boilerplate code when we want to make a container component.

Usually, when we want to connect a component with our Redux state, we’ll do the boilerplate code like this:
// YourComponent.jsimport React, { PureComponent } from 'react'
import { connect } from ‘react-redux’const mapStateToProps = (state) => {
// Decide your state that will be the component's props
...
return stateToProps
}const mapDispatchToProps = (state) => {
// Decide your action creators that will be the component's props
...
return dispatchToProps
}class YourComponent extends PureComponent {
...
}export default connect(mapStateToProps, mapDispatchToProps)(YourComponent)
However, this code has no abstraction at all about connecting our own component to Redux store. We have to rewrite these boilerplate code, such as import connect, export default connect(mapStatetoProps, mapDispatchToProp)(YourComponent)
, etc for every time when we want to create a container component.
This article (The Importance Of Abstraction in JS) teach me that abstraction is really useful, especially if you have a dependency with other 3rd party, such as Redux, so we can easily address the breaking changes problem ( the implementation is defined only in one place)
How can we make this code better? Easy, just create a HOC that will receive the child component, mapStateToProps
, and Action Creators.
// buildReduxContainer.jsimport React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'import PropTypes from 'prop-types'export default function (ComposedComponent, mapStatetoProps,
actionCreators) {
class ReduxContainer extends React.PureComponent {
constructor (props) {
super(props)
const { dispatch } = props
this.boundActionCreators = bindActionCreators(actionCreators,
dispatch)
} render () {
return (
<ComposedComponent
{...this.props}
{...this.boundActionCreators}
/>
)
}
} ReduxContainer.propTypes = {
dispatch: PropTypes.func
} ReduxContainer.defaultProps = {
dispatch: () => {}
} return connect(mapStatetoProps)(ReduxContainer)
}
bindActionCreators
will turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch
call so they may be invoked directly. With this approach, we can reduce and make our boilerplate code cleaner:
// YourComponent.jsimport React, { PureComponent } from 'react'
import * as actionCreators from './actions'import ReduxContainerHOC from 'buildReduxContaner'const mapStateToProps = (state) => {
// Decide your state that will be the component's props
...
return stateToProps
}class YourComponent extends PureComponent {
...
}export default ReduxContainerHOC(YourComponent, mapStateToProps,
actionCreators)
If there are any breaking changes in redux
or react-redux
, we just change the ReduxContainerHOC
code, not the whole code in our container components.
Conclusion
In this article, we can use the HOC concept to solve our redux implementation in container components. Always see and review your code if there are any possibility to compose your components for a better and scalable solution.
If you have any questions, feel free to leave a comment! 🙋