Redux thinks that a thunk is a reducer when being dispatched within a callback

27 views Asked by At

I have a React/Redux application with thunk middleware installed and working propertly - all other thunk dispatches work fine. I have a thunk that is being dispatched along with a function handler that it itself needs to dispatch something.

Here is an example:

dispatch(triggerModal({
    payload: { key: 'value' },
    onClose: () => {
        dispatch(clearStuffAndCloseModal())
    }
}))

And in another file:

export const triggerModal = ({ payload, onClose }) => dispatch => {
    const data = await fetchSomeData(payload)
    // Do other random stuff.

    if (!data) {
        onClose()
    }
}

export const clearStuffAndCloseModal = () => dispatch => {
    console.log('start')

    dispatch(clearStuff()) // The error seems to be happening here as only 'start' is printed

    console.log('end')

    dispatch(closeModal())
}

When running this and triggering the onClose, I get an error in the browser console:

redux.js:208 Uncaught (in promise) Error: Reducers may not dispatch actions

From what I can tell, it seems that Redux thinks that clearStuffAndCloseModal function is a reducer and gets upset when I'm trying to dispatch from a reducer. However, it's not a reducer but a thunk so I'm not quite sure how to fix this. I'm wondering if it's an issue with the dispatch call within the onClose callback.

Any help would be greatly appreciated.

1

There are 1 answers

0
Drew Reese On BEST ANSWER

I don't see any overt issue(s) with the action code specifically, but instead of passing a callback through the action payload to "chain" handlers/actions, I suggest the code should return the data value back to the caller and then dispatch the additional action(s) based on the result.

Example:

export const triggerModal = (payload) => async (dispatch) => {
  const data = await fetchSomeData(payload);
  // Do other random stuff.

  return data;
};

export const clearStuffAndCloseModal = () => dispatch => {
  console.log('start');
  dispatch(clearStuff());
  console.log('end');
  dispatch(closeModal());
};
const someFunction = async () => {
  const data = await dispatch(triggerModal({ key: 'value' }));

  if (!data) {
    dispatch(clearStuffAndCloseModal());
  }
};

or

const someFunction = async () => {
  const data = await dispatch(triggerModal({ key: 'value' }));

  if (!data) {
    dispatch(clearStuff());
    dispatch(closeModal());
  }
};