pandemic
pandemic

Reputation: 1195

Chaining promises with action reducers in React

I have a method which is firing two http requests to API to get the data.

getServerDetails(this.props.match.params.id) //1
            .then(res => {
                this.props.getServerDetailsAction({ success: true, data: res.data })

                if (!_.isEmpty(res.data)) {
                    return getServerScomAlerts(res.data.ServerName) //2
                }
            })
            .catch((err) => { //3
                this.props.getServerDetailsAction({ success: false, error: err })
            })
            .then(res => {
                if (!_.isEmpty(res)) {
                    this.props.getServerScomAlertsAction({ success: true, data: res.data })
                }
            })
            .catch((err) => { //4
                this.props.getServerScomAlertsAction({ success: false, error: err })
            })

getServerDetails (1) and getServerScomAlerts (2) methods are returning promises. getServerScomAlerts (2) is dependent on the result of getServerDetails (1)

The problem is that if error occurs in getServerScomAlerts (2) the first catch block (3) is executed. Is there a way how to get the data from the first method (1) (without accessing store) and at the same time jump to the corresponding catch block (4) if the error occurs?

Upvotes: 0

Views: 81

Answers (3)

Hamed
Hamed

Reputation: 1381

Something like this might give you an idea how to achieve your goal. Instead of having nested then, you can use async/await and it waits for the result of each call before proceeding to the next:

export const actionCreators = {
    myFunc: (param1, param2) => async (dispatch, getState) => {
        try {
            const response1 = await fetch(param1);
            const data1 = await response.json();

            const response2 = await fetch(param2);
            const data2 = await response2.json();

        } catch (err) {
            console.log(err);
        }
    }
}

Upvotes: 1

adamrights
adamrights

Reputation: 1731

This is a good use case for .finally() method, currently in draft specification according to the MDN. It allows you to remove duplication logic, by running the method after the promise is resolved or rejected.

As shown in the MDN example:

let isLoading = true;

fetch(myRequest).then(function(response) {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
  })
  .then(function(json) { /* process your JSON further */ })
  .catch(function(error) { console.log(error); /* this line can also throw, e.g. when console = {} */ })
  .finally(function() { isLoading = false; });

If you want to use the feature right now, you can consider using Bluebird for your promise implimentation, which in some cases is faster, and should be easy to upgrade from as the method is standarized

Upvotes: 0

duc mai
duc mai

Reputation: 1422

It is really interesting with your problem since you want to do multiple actions which are slightly different from each other only :). I would rewrite as following

const getServerScomAlertsAction = (success, props) => (res) => {
  success = success && !_.isEmpty(res);
  props.getServerScomAlertsAction(success ? { success, data: res.data } : { success, error: res });
};
const getServerDetailsAction = (success, props) => (res) => {
  props
    .getServerDetailsAction(success ? { success, data: res.data } : { success, error: res })
    .then(getServerScomAlertsAction(true, props))
    .catch(getServerScomAlertsAction(false, props));
};

getServerDetails(this.props.match.params.id)
  .then(getServerDetailsAction(true, this.props))
  .catch(getServerDetailsAction(false, this.props));

Upvotes: 0

Related Questions