Presentational and Container Components for React with Redux

Presentational and Container Components for React with Redux
SHARE

In this post I'll briefly describe small refactoring of React component based on this article

I'm creating an SPA using React and Redux library for Flux architecture.

MyComponent - old way

react-component-1

MyComponent.js

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { myAction } from '../actions' // actions
import styles from './styles.scss' // CSS Modules
class MyComponent extends Component {
render() {
return (<div className={styles.myClass}>MyComponent...</div>)
}
}
MyComponent.propTypes = {
propFromUrlParam: PropTypes.string.isRequired,
propFromState: PropTypes.string.isRequired,
myAction: PropTypes.func.isRequired
}
function mapStateToProps(state, props) {
let { propFromUrlParam } = props.params; // props from URL params
let { propFromState } = state; // props from state
return {propFromUrlParam, propFromState}
}
export default connect(mapStateToProps, {
// mapping methods to component
myAction
})(MyComponent)

This file is going to be really big and one of best practices is to divide it into two logical parts:

Dumb and Smart or Container and Presentational components. All the explanation you can find here.

I'll just show how it looks in my case after dividing. So,

MyComponent - new way

react-component-2

MyComponent.js the presentational component:

import React, { Component, PropTypes } from 'react'
import styles from './styles.scss' // CSS Modules
class MyComponent extends Component {
render() {
return (<div className={styles.myClass}>MyComponent...</div>)
}
}
MyComponent.propTypes = {
propFromUrlParam: PropTypes.string.isRequired,
propFromState: PropTypes.string.isRequired,
myAction: PropTypes.func.isRequired
}
export default MyComponent

MyComponentContainer.js the container component:

import MyComponent from './MyComponent' // presentational component
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { myAction } from '../actions' // actions
function mapStateToProps(state, props) {
let { propFromUrlParam } = props.params; // prop from URL params
let { propFromState } = state;
return {propFromUrlParam, propFromState}
}
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({
// mapping methods to component
myAction
}, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

And a small helper index.js which is used just for convenience while importing the component and looks like this:

export default from './MyComponent' // container components

Now you may import the MyComponent wherever you need it

import MyComponent from './components/MyComponent' // will import index.js