React-redux-starter-kit: How to dispatch actions in a container?

Created on 6 Jul 2016  路  7Comments  路  Source: davezuko/react-redux-starter-kit

class SomeContainer extends Component {
  //Like this
  componentDidMount() {
    dispatch(someAction())
  }
}

Most helpful comment

The comment cited by @brianzinn is the core of your solution. A container does not concern itself with presentation; _simply said (sic)_ a pure container is not a React.Component... though directs 1..* React.Component.

See https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.eznb2j8bo

As @nie-xin eventually mentioned; connecting the component will give you access to dispatching actions;

import { someReduxAction } from './SomeReduxActions';
export class SomeView extends React.Component {
  // someReduxAction is now available via this.props.someReduxAction
}
export default connect(null, {someReduxAction})(SomeView);

It all comes down to semantics.. your "container" is not a _container_ as people expect it to be. Though it is fine as it is. So how to do what you want to do?

Maybe something like;

import { someReduxAction } from './SomeReduxActions';
export class SomeView extends React.Component {
  componentDidMount() {
    this.props.someReduxAction();
  }
}
export default connect(null, {someReduxAction})(SomeView);

All 7 comments

You will need to use the store context:

containerXxx.contextTypes = {
  store: React.PropTypes.object.isRequired
}

Then on your method, you can get dispatch function from store:

const store = this.context.store
store.dispatch(someAction())

Anyway, avoid doing this. The connect function should be fairly enough to link actions.

The comment in CounterContainer would seem to indicate that a container shouldn't have a componentDidMount() from React Component.
/* This is a container component. Notice it does not contain any JSX, nor does it import React. This component is **only** responsible for wiring in the actions and state necessary to render a presentational component - in this case, the counter: */

Following that example, in your container the second argument of connect (mapActionCreators) will pass on the action creators that don't need a store reference (the functions are able to dispatch automatically). Then in the presentational component like the layout you can pass the actions creators (which are functions) through as props, so in your presentational component:
...'
componentDidMount() {
this.props.someAction()
}`

The starter kit is just a guide, so go with what works best for you. Search google for "abramov Presentational Container components" for more ideas.

The comment cited by @brianzinn is the core of your solution. A container does not concern itself with presentation; _simply said (sic)_ a pure container is not a React.Component... though directs 1..* React.Component.

See https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.eznb2j8bo

As @nie-xin eventually mentioned; connecting the component will give you access to dispatching actions;

import { someReduxAction } from './SomeReduxActions';
export class SomeView extends React.Component {
  // someReduxAction is now available via this.props.someReduxAction
}
export default connect(null, {someReduxAction})(SomeView);

It all comes down to semantics.. your "container" is not a _container_ as people expect it to be. Though it is fine as it is. So how to do what you want to do?

Maybe something like;

import { someReduxAction } from './SomeReduxActions';
export class SomeView extends React.Component {
  componentDidMount() {
    this.props.someReduxAction();
  }
}
export default connect(null, {someReduxAction})(SomeView);

As @nie-xin .

You will need to use the store context:

containerXxx.contextTypes = {
  store: React.PropTypes.object.isRequired
}

in customize function, you should bind in

  constructor (props, context) {
    super(props, context)
    this.functionName = this.functionName.bind(this)
  }

  functionName () {
     const store = this.context.store
     store.dispatch(someAction())    
  }

Closing as resolved, thanks for everybody's contributions.

@davezuko in some cases it would be nice to be able to handle this without passing the logic down to the presentational component and without the container having to extend React.Component.

I asked about this on Stack Overflow and have a possible solution that I'd be keen to get feedback on:

import { connect } from 'react-redux'

import MyComponent from '../components/mycomponent'
import { fetchMyData } from '../actions/mydata'

const mapStateToProps = state => ({
  dataId: state.activeDataId,
  myData: state.myData[state.activeDataId]
})

const mapDispatchToProps = { fetchMyData }

const mergeProps = (stateProps, dispatchProps) => {
  if (!stateProps.myData) {
    dispatchProps.fetchMyData(stateProps.dataId)
  }
  return stateProps
}
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(MyComponent)

I think that I understand what you are trying to do now. It looks like you are ensuring the data for your presentational component is available without wanting the presentation component to have that responsibility. I do agree that the presentational component should not have to take care of that, but feel personally that I don't want the container to do that either. One way is to put methods in routes. ie:

onEnter(next, replace) {
    let activeDataId = next.params['id']

    // route is dispatching selection.
    store.dispatch(selectActiveData(Number(activeDataId)))
  }

I don't normally use routes that way. Generally I handle these use-cases using redux-saga (there is a recipe available), so whenever state.activeDataId changed the saga (by listening for action(s)) would ensure the data was loaded (could also be done with a thunk) without side-effects. Doing so I have never needed a container to do anything besides map state and props. It's not hard to argue that a saga is overkill, so maybe more people would find your suggestion useful! :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

macnibblet picture macnibblet  路  3Comments

kolpav picture kolpav  路  4Comments

renanvalentin picture renanvalentin  路  5Comments

dfalling picture dfalling  路  5Comments

liubko picture liubko  路  4Comments