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