Tuomas Toivonen Tuomas Toivonen - 4 months ago 180
Javascript Question

Redux thunk: return promise from dispatched action

Is it possible to return promise/signal from action creator, resolved when Redux thunk has successfully dispatched certain action?

Consider this action creator:

function doPost(data) {
return (dispatch) => {
dispatch({type: POST_LOADING});
Source.doPost() // async http operation
.then(response => {
dispatch({type: POST_SUCCESS, payload: response})
})
.catch(errorMessage => {
dispatch({type: POST_ERROR, payload: errorMessage})
});
}
}


I want to call some function asynchronously in the component after calling doPost action creator when Redux has either dispatched POST_SUCCESS or POST_ERROR actions. One solution would be to pass the callback to action creator itself, but that would make code messy and hard to grasp and maintain. I could also poll the Redux state in while loop, but that would be inefficient.

Ideally, solution would be a promise, which should resolve/reject when certain actions (in this case POST_SUCCESS or POST_ERROR) gets dispatched.

handlerFunction {
doPost(data)
closeWindow()
}


The above example should be refactored, so closeWindow() gets called only when doPost() is successful.

Answer

Sure, you can return promise from async action:

function doPost(data) {
    return (dispatch) => {
        dispatch({type: POST_LOADING});
        // Returning promise.
        return Source.doPost() // async http operation
            .then(response => {
                dispatch({type: POST_SUCCESS, payload: response})
                // Returning response, to be able to handle it after dispatching async action.
                return response;
            })
            .catch(errorMessage => {
                dispatch({type: POST_ERROR, payload: errorMessage})
                // Throwing an error, to be able handle errors later, in component.
                throw new Error(errorMessage)
            });
    }
}

Now, dispatch function is returning a promise:

handlerFunction {
  dispatch(doPost(data))
      // Now, we have access to `response` object, which we returned from promise in `doPost` action.
      .then(response => {
          // This function will be called when async action was succeeded.
          closeWindow();
      })
      .catch(() => {
          // This function will be called when async action was failed.
      });
}
Comments