2

I have a container component within my React and Redux application:

import { connect } from 'react-redux'

import MyComponent from '../components/mycomponent'

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

export default connect(mapStateToProps)(MyComponent)

If state.myData[state.activeDataId] does not exist then I want to dispatch an action to fetchMyData or fetchMyDataIfNeeded.

Note that, at the moment, my container does not contain any JSX, it just forwards props to a presentational component. I have seen this being called a 'Pure Container' though I'm not sure if that's a common term.

Is there a common pattern to dispatch actions from a Pure Container? I am thinking without:

  • expecting the presentational component to worry about this logic by passing an onLoad event to it
  • making the container a React.Component and triggering via componentDidMount

Is it a bad idea to dispatch actions from mapStateToProps, mapDispatchToProps or mergeProps?

Alasdair McLeay
  • 2,572
  • 4
  • 27
  • 50
  • It is a bad idea to dispatch actions in your container methods, it seems to be common practice either do it in the `component*` functions in your child component where needed as the `connect` HOC passes the `dispatch` function to your child component in `this.props`. – Dan Mason Aug 16 '17 at 14:18

3 Answers3

1

As noted elsewhere, doing this in the container is a bad idea.

Instead of worrying about this in the container, it makes sense to fetch the data conditionally in your component. I know you mentioned not wanting to extend react.component, but you should definitely consider making this component a class in order to fetch data in a component lifecycle hook.

As detailed in another answer, connect takes a second argument of mapDispatchToProps. Pass in the fetchData dispatcher there (example of how to do this here.)

Then, in your component you can check myData. If it is not there, then you dispatch via

this.props.whatYouCalledDispatch()
gabrielwr
  • 198
  • 9
  • Thanks! Can you expand on why it's a bad idea to dispatch an action in a container? Are there any specific unwanted side effects? – Alasdair McLeay Aug 17 '17 at 10:37
  • 1
    Pure containers are really only meant to connect the specified component to the store by passing the state and dispatch methods necessary. Then, the component (which should be a class, not presentational) will take care of the business logic of retrieving the data if it needs it. Would be strange to call dispatch in the container since it has no connection to the lifecycle of the component, and therefore could lead to some unwanted side effects (i.e. not having dispatched at the correct/necessary time in the lifecycle). Please up vote or select this answer if this helps. – gabrielwr Aug 17 '17 at 14:43
1

Yes, it is a bad idea to dispatch any action in container. In your case, the best approach is:

  • Map your state, action creator to component props
  • Check the props in componentDidMount (or componentDidUpdate) and fetchDataYouNeed, then component will be updated

Your container should be:

import { connect } from 'react-redux';
import {fetchDataYouNeed} from './actions
import MyComponent from '../components/mycomponent';

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

    const mapDispatchToProps = (dispatch) => {
      return {
        fetchDataYouNeed: ()=>{
          dispatch(fetchDataYouNeed());
        }
      };
    };

    export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

Your component

class YourComponent extends Component{ 

  componentDidMount(){
    let {myData, activeDataId} = this.props;
    if(myData && !myData[activeDataId]){
      this.props.fetchDataYouNeed();
    }
  }

  render(){
    ....
  }
}

Learn more here https://facebook.github.io/react/docs/react-component.html#componentdidmount

gabrielwr
  • 198
  • 9
hien
  • 1,988
  • 2
  • 17
  • 13
  • Thanks! Can you expand on why it's a bad idea to dispatch an action in a container? Are there any specific unwanted side effects? – Alasdair McLeay Aug 17 '17 at 10:37
  • 1
    What is container? What is component? Container is just smart component (connected with redux store). Container just need to do one thing: get states, map them + action creators to component. The best time for changing state (dispatch action) is when states is stable (component rendered). The reason is we don't want chaos of changing states, it's not good for management and performance – hien Aug 18 '17 at 03:17
0

This seems to work, though I'm not sure if it has any unintended effects:

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)

Alternatively, brianzinn suggested that by using Redux Saga to manage side effects, this issue becomes redundant.

Alasdair McLeay
  • 2,572
  • 4
  • 27
  • 50