1

How to get normal JSON object from Promise Object in react-redux?

My action.js contains:

  export function allEmp() {
      let url = "employees?access_token=";
      let result = ApiCall.getApiCall(url)
      .then(function (response) {
         return response;
       })
       .catch(function (error) {
         return error;
       });
       console.log("result",result);
       return {
         type: "ALL_EMP",
         payload: new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(result);
                }, 2000);
            })
       };
     }

my API call configuration is:

getApiCall(url) {
    let base_url = "http://192.168.1.151:3000/api/";
    let api_token = "1f7169e92c1d0722db575b877707cf0b88b8f0ad";
    let fetch_url = base_url + url + api_token;
    let myHeaders = new Headers({
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    });
    return fetch(fetch_url, {
      method: "GET",
      headers: myHeaders
    })
    .then(function(response) {
      if (response.ok) {
        return response.json();
      } else {
        var error = new Error(response.statusText);
        error.response = response;
        throw error;
      }
    })
    .then(function(json) {
      return json;
     })
  }

My store.js :

import {createStore, combineReducers, applyMiddleware} from "redux";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";

import userDetails from "./reducers/User_reducer";

export default createStore(
    combineReducers({
        userDetails
    }),
    {},
    applyMiddleware(thunk, promise())
);

But here I'm getting Promise object as a result. So that when I'm assigning in payload it is getting as undefined. How should I manipulate it when I'm sending the response as payload.

Can anyone give me some suggestion?

Riya Kapuria
  • 9,170
  • 7
  • 18
  • 32
  • This solution is working. But in that example axios has been used and I'm using fetch. Thanks. – Riya Kapuria Jan 09 '18 at 09:53
  • Hi, Shubham this method is not working on the post request. Can you please help ?? export function loginDetails(input) { let url = "admins/api_login"; debugger; return (dispatch) => { dispatch({type: "LOGIN_FETCH"}); ApiCall.postApiCall(url, input) .then((response) => { dispatch({type: "LOGIN_SUCCESS", payload: response}); }) .catch((error) => { dispatch({type: "LOGIN_FAIL", payload: error}); }) } } – Riya Kapuria Jan 10 '18 at 12:28
  • `const mapStateToProps = (state) => { return { sessionReducer: state.sessionReducer }; }; const mapDispatchToProps = (dispatch) => { return { loginDetails: (login_details, loggedIn, error, payload) => { dispatch(loginDetails(login_details, loggedIn, error, payload)); } }; }; export default connect(mapStateToProps, mapDispatchToProps)(Signin);` – Riya Kapuria Jan 11 '18 at 05:32
  • `const sessionReducer = (state = {INITIAL_STATE},action) => { switch(action.type){ case "LOGIN_FETCH": state={ ...state, login_details: action.payload, loggedIn: false }; break; case "LOGIN_SUCCESS": state={ ...state, loggedIn: true, error: null }; break; case "LOGIN_FAIL": state={ ...state, loggedIn: false, error: action.payload }; break; default: break; } return state; }; export default sessionReducer;` – Riya Kapuria Jan 11 '18 at 05:37
  • now the problem is API call is not happening. – Riya Kapuria Jan 11 '18 at 05:51
  • Is your loginDetails function getting executed, also is it calling `ApiCall.postApiCall(url, input)`, can you log and check, are there any errors – Shubham Khatri Jan 11 '18 at 06:01
  • `export function loginDetails(input) { let url = "admins/api_login"; let result = ApiCall.postApiCall(url, input) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); console.log(result); return { type: "LOGIN_SUCCESS", payload: result }; } ` I've checked like this. It is getting the response. But in dispatch way, it is not happening. – Riya Kapuria Jan 11 '18 at 06:05
  • I see that in your original attempt you have a `debugger;` statement in your original attempt, can you remove that – Shubham Khatri Jan 11 '18 at 06:11
  • till the debugger, it is working. after that debugger its not working. – Riya Kapuria Jan 11 '18 at 06:15
  • Can we discuss in chat?? – Riya Kapuria Jan 11 '18 at 06:17
  • Where exactly ?? – Shubham Khatri Jan 11 '18 at 06:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/162951/discussion-between-riya-kapuria-and-shubham-khatri). – Riya Kapuria Jan 11 '18 at 06:18

2 Answers2

2

react-redux does not support asynchronous action creators out-of-the-box, so you'll need to add a dependency to your project.

Take a look at the redux-thunk middleware, which adds support for asynchronous action creators.

The idea with redux-thunk is that your action creator will trigger another action once the asynchronous code resolves.

In your case, you would have an allEmp action creator that calls another action receiveAllEmp once the Promise resolves:

allEmp Action Creator (using redux-thunk)

export function allEmp() {

    return (dispatch) => {

        return ApiCall.getApiCall(url).then((response) => {

            // Dispatch the receiveAllEmp action

            dispatch(receiveAllEmp(response));

            return response;
        });
    };
}

receiveAllEmp Action Creator (normal action creator)

export function receiveAllEmp(response) {
    return {
        type: "ALL_EMP",
        payload: response,
    };
}
Christian Santos
  • 5,386
  • 1
  • 18
  • 24
  • Agreed, redux-thunk is great. But as action creators can dispatch other action creators (potentially as the result of async operations), you can certainly write asynchronous action creators using promises - they just can't return promises. – Joshua R. Jan 09 '18 at 06:19
1

Promises represent asynchronous processes whose may not be available immediately. They provide a way to trigger a handler when the result is ready (so your Javascript can go on and get other work done).

To access their result, you place a handler in a .then method which is called at resolution and receives the result as an argument.

See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

You might consider writing your function:

export function allEmp() {
  p = new Promise();

  let url = "employees?access_token=";
  ApiCall.getApiCall(url)
  .then(function (response) {
     console.log("result",result);    
     p.resolve({
                type: "ALL_EMP",
                payload: response})
            })
   .catch(function (error) {
      console.log("error",error);  
     p.reject(error)
   });

 return p  // allEmp now returns a promise which gives it a .then() method to contain your handler code.
 }

Then call your function like this:

allEmp().then(
 function(res){/*handle it here, not called until async resolves, receives result*/},
 function(err){/*or resolves to error, receives error*/}
 )

You might consider also having a look at the await/async syntax which makes it appear as if you code is waiting for async operations and can enhance readability in the majority of cases.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Joshua R.
  • 2,282
  • 1
  • 18
  • 21