Guy Guy - 1 month ago 6
React JSX Question

Dispatching an action in a specific component based on a state change

In redux I want to show a modal if a specific state changes. It is only relevant if the user is viewing a specific component. I used the container's mapDispatchToProps:

const mapDispatchToProps = (stateProps, dispatchProps, ownProps) => {

const {dispatch} = dispatchProps;
const {appType, publishState, publishStages} = stateProps;
const isWebsite = (appType !== 'MOBILE');

switch (publishState.stage) {
case publishStages.GENERATING_BUILDREQUEST:
case publishStages.WAITING:
case publishStages.WORKING:
case publishStages.UPLOADING:
dispatch(showModal(modalTypes.PUBLISH_MODAL, {isWebsite}));
break;

case publishStages.COMPLETED:
dispatch(showModal(modalTypes.PUBLISH_SUCCESS_MODAL, {isWebsite}));
break;

case publishStages.ERROR:
dispatch(showModal(modalTypes.PUBLISH_FAILURE_MODAL, {isWebsite}));
break;

default:
dispatch(closeModal());
}

return {...


However this doesn't feel elegant as one wouldn't expect a mapping function to tweak state. Any ideas how to properly achieve this?

Answer

I wouldn't indeed call dispatch in the mapDispatchToProps function. This function should be "pure" and just return a mapping without any side effect.

Since you know what action should trigger the modal ie. when publicStages is set to a particular value, I would suggest taking care of changing the state in 2 possible ways:

  1. You can do this in the reducer. When you change publicStages, the reducer also has access to the modal state, and changes it too.
  2. In the action. In the action that changes PublicStages, call the action to open/close the modal depending on what you do with publicStages. Be mindful that calling dispatch is supposed to be async. In this case, you also need to dispatch from the action, so you have to pass the dispatch function down to the action.

EDIT: following the discussion in the comments - and for completeness - if the modal is displayed only as part of one visual component, you could also store its open/closed state in the component itself and manage it in componentWillMount and componentWillUpdate. An interesting read about that from Redux's creator Dan Abramov is You Might Not Need Redux