2
votes

I am trying to chain dispatches with redux-thunk. I have 2 action creator as below:

getResourceLinks:

export const getResourceLinks = () => {
  return dispatch => {
    let req = {
      url: getRootUrl(),
      header: {
        Accept: 'application/json'
      }
    };
    return request(req).then(res => {
      dispatch({
        type: ActionTypes.RESOURCE.LOAD_URL_SUCCESS,
        payload: res.body
      });
    }).catch(err => {
      dispatch({
        type: ActionTypes.RESOURCE.LOAD_URL_ERROR,
        payload: err
      });
    });
  }
};

and loadAppliances:

export const loadAppliances = () => {
  return (dispatch, getState) => {
    return dispatch(getResourceLinks()).then(res => {
      const {resources} = getState();
      let req = {
        url: getResourceLink(Resources.Appliances, res.body),
        header: {
          Accept: 'application/json'
        }
      };
      request(req).then(res1 => {
        dispatch({
          type: ActionTypes.APPLIANCE.LOAD_SUCCESS,
          payload: res1.body
        });
      }).catch(err => {
        dispatch({
          type: ActionTypes.APPLIANCE.LOAD_ERROR,
          payload: err
        });
      });
    });
  };
};

I am facing with an error: Uncaught TypeError: Cannot read property 'then' of undefined at line 3 in loadAppliances action. Promise was returned correctly, wasn't it? Am I doing wrong something? I've seen carefully examples of thunk-redux but I don't still find out what was wrong.

Update. Here is request:

import superagent from 'superagent';
import superagentPromisePlugin from 'superagent-promise-plugin';
import {RequestMethods} from '../constant';

const request = ({url, method = RequestMethods.GET, param, body, header}) => {
  let methodStr;
  switch (method) {
    case RequestMethods.POST:
      methodStr = 'POST';
      break;
    case RequestMethods.PUT:
      methodStr = 'PUT';
      break;
    case RequestMethods.DELETE:
      methodStr = 'DELETE';
      break;
    default:
      methodStr = 'GET';
      break;
  }
  let req = superagent(methodStr, url).use(superagentPromisePlugin);
  //set header
  if (header) {
    req.set(header)
  }
  //set param
  if (param) {
    req.query(param)
  }
  //set body
  if (body) {
    req.send(body)
  }
  return req;
};

export default request;
1
can you provide request functionKokovin Vladislav
@Utro I've updated my question with request function.An Nguyen

1 Answers

3
votes

The problem here is that dispatch does not return your promise. It actually returns the dispatched action itself. (reference).

return dispatch(getResourceLinks()).then(res => {
                                   ^--- this is the problem

The way I would approach this is to dispatch an action after your first successful call and store any pertinent information in the state, then dispatch the next call and store its response.

Example

const getResourceLinks = () => {
  return request({
    url: getRootUrl(),
    header: {
      Accept: 'application/json'
    }
  });
};

const getAppliances = (appliances) => {
  return request({
    url: getResourceLink(Resources.Appliances, appliances),
    header: {
      Accept: 'application/json'
    }
  })
};

export const loadAppliances = () => {
  return (dispatch, getState) => {
    getResourceLinks()
      .then(res => {
        dispatch({
          type: ActionTypes.RESOURCE.LOAD_URL_SUCCESS,
          payload: res.body
        });

        return getAppliances(res.body)
          .then(res1 => {
            dispatch({
              type: ActionTypes.APPLIANCE.LOAD_SUCCESS,
              payload: res1.body
            });
          })
          .catch(err => {
            dispatch({
              type: ActionTypes.APPLIANCE.LOAD_ERROR,
              payload: err
            });
          });
      })
      .catch(err => {
        dispatch({
          type: ActionTypes.RESOURCE.LOAD_URL_ERROR,
          payload: err
        });
      });
  }
}

You also might want to take a look at redux-saga