Generic dataloader for redux-thunk using axios I am developing an application where there are lots of async actions. I wanted to go with redux-saga but most have insisted to continue with redux-thunk. In redux-thunk, inside each action we have to work with async operation using then, dispatch, catch, etc. This makes looks actions so messy and lots of code will be repeated. I wanted to create a generic dataLoader for the use of redux-thunk and axios.

Here is my attempt:

export class Company {
/**
* Generic api data loader
*/
static dataLoader(apiUri, onSuccess, onError, data, ...actionArguments) {
  const requestURL = `${API_BASE}${apiuri}`;
  try {
    let options;
    if (data !== undefined) {
      // if we have data to post
      options = {
      method: 'POST',
      url: requestURL,
      body: JSON.stringify(data),
      headers: {
         'Content-Type': 'application/json',
         'X-Requested-With': 'XMLHttpRequest',
      },
      };
    }
  }
  return function(dispatch) {
    axios(options)
    .then(response =&gt; {
      dispatch({
        type: onSucess,
        payload: response.data
      });
    })
    .catch(error =&gt; {
      dispatch({ type: onError, payload: err});
    });
  }
}

static get(apiUri, onSuccess, onError, ...actionArguments) {
    return this.dataLoader(apiUri, onSuccess, onError, undefined, ...actionArguments);
  }

  /*
   * Shorthand POST function
   */
  static post(apiUri, onSuccess, onError, data, ...actionArguments) {
    return this.dataLoader(apiUri, onSuccess, onError, data, ...actionArguments);
  }

}


I want to convert the following code to further this one:

export function showResultofApartment() {
  return (dispatch) =&gt; {
    dispatch({ type: 'APARTMENT_FETCH_START' });
    const token = localStorage.getItem('token');
    return axios.get(`${API_URL}/newoffers/apartment/`)
    .then((response) =&gt; {
      console.log('response apart', response.data);
        dispatch({ type: 'APARTMENT_FETCH_SUCCESS', payload: response.data });
    })
    .catch((err) =&gt; {
      dispatch({ type: 'APARTMENT_FETCH_FAILURE', payload: err });
    });
  };
}


to such or more efficient than this:

export function showResultofApartment() {
  return(dispatch) =&gt; {
    dispatch({ type: APARTMENT_FETCH_START });
    const token = localStorage.getItem('token');
    return Company.get('/apartments', APARTMENT_FETCH_SUCCESS, APARTMENT_FETCH_ERROR);
    // if post then Company.post('/apartment', APARTMENT_POST_SUCCESS, APARTMENT_POST_ERROR, data)
  }
}


I have not tested this. I am just throwing my idea through code to get other experts idea on how I should handle such case for a more efficient technique without using other more external libraries.
This is one of the problems with async actions in redux-thunk. As you point out you have to create constants for "APARTMENT_FETCH_STATUS" and manually dispatch actions of this type before and after the request has been done. 

The redux-promise-middleware library actually does all this for you. You simply create an action like so:

const foo = () =&gt; ({
  type: 'FOO',
  payload: new Promise()
});


and the library will take care of dispatching an action of type "FOO_PENDING", and then of type "FOO_FULFILLED" when the promise has resolved. With redux-promise-middleware your actions would become something like this:

const showResultOfApartment = () =&gt; ({
    type: "FETCH_APARTMENT",
    payload: axios.get("http://api.com/apartments").then(result =&gt; result.data)
})


In your reducer you would create handlers for "FETCH_APARTMENT_PENDING", "FETCH_APARTMENT_FULFILLED" and "FETCH_APARTMENT_REJECTED". In the case where the promise fulfills or rejects, you also get the result of the promise by accessing action.payload. An example of what it could look like:

function apartmentReducer(state, action){
    if(action.type === "FETCH_APARTMENT_PENDING"){
        return Object.assign({}, state, { loading: true })
    }
    else if(action.type === "FETCH_APARTMENT_FULFILLED"){
        return Object.assign({}, state, { loading: false, apartment: action.payload })
    }
    else if(action.type === "FETCH_APARTMENT_REJECTED"){
        return Object.assign({}, state, { loading: false, error: action.payload })
    }
    return state;
}


redux-promise-middleware

Introduction to redux-promise-middleware