This is my typical decorator stack for a 'smart component' used as the component for react-router
route.
Note some code is missing here but this should give you the idea.
Example usage:
StateDetailsScene.js
import React from 'react'
import _ from 'lodash'
import route from 'core/decorators/route'
import {listActivity} from 'esa/actions/activity'
import {stateSelector} from 'esa/selectors/states'
import {statsSelector} from 'esa/selectors/stats'
import {stateLegislatorsSelector} from 'esa/selectors/legislators'
import {activityListSelector} from 'esa/selectors/activity'
import StateLayout from 'esa/components/layouts/state/StateLayout'
import SectionedView from 'esa/components/sectioned-view/SectionedView'
import Stats from 'esa/components/stats/Stats'
import Activity from 'esa/components/activity/Activity'
import Legislators from 'esa/components/legislators/Legislators'
import Loading from 'core/components/loading/Loading'
import {detailsLoading} from 'theme/styles/scenes'
@route({
loader: ({dispatch, params}) => [
dispatch(listActivity({query: {tags: `states:${params.stateId}`}}))
],
selectors: [
stateSelector,
statsSelector,
stateLegislatorsSelector,
activityListSelector
],
toJS: true
})
class StateDetailsScene extends React.Component {
static propTypes = {
params: React.PropTypes.object,
state: React.PropTypes.object,
stats: React.PropTypes.object,
activity: React.PropTypes.object,
legislators: React.PropTypes.object
}
static defaultProps = {
activity: {}
}
getSections () {
let sections = []
if (this.props.stats) {
sections.push({
id: 'stats',
title: 'Stats',
showHeader: false,
render: () => <Stats stats={this.props.stats}/>
})
}
if (this.props.legislators) {
sections.push({
id: 'legislators',
title: 'Legislators',
showHeader: true,
render: () => <Legislators legislators={_.values(this.props.legislators)}/>
})
}
if (this.props.activity.list && this.props.activity.list.length) {
sections.push({
id: 'activity',
title: 'Recent Activity',
showHeader: true,
render: () => <Activity activity={this.props.activity.list}/>
})
}
return sections
}
render () {
let sections = this.getSections()
return this.props.state ? (
<StateLayout state={this.props.state}>
{sections.length ? (
<SectionedView sections={sections}/>
) : (
<Loading spinnerSize='large' fontSize={16} style={detailsLoading}/>
)}
</StateLayout>
) : null
}
}
export default StateDetailsScene
selectors/states.js
import {createSelector} from 'reselect'
// Select a state
export const stateSelector = createSelector(
(state) => state.states,
(state, props) => {
if (props.params.stateId) {
return props.params.stateId
}
if (props.params.districtId) {
return props.params.districtId.substr(0, 2)
}
return null
},
(states, stateId) => {
return {
state: states.getIn(['states', stateId])
}
}
)
Thanks for sharing that, I have turned this into a package : https://www.npmjs.com/package/react-redux-immutable
That's it your
mapStateToProps
function can return immutable objects and your connected React component will receive JS objects.