Redux-thunk: API response keeps pending

2019-08-21 07:17发布

I am trying to develop an application, that is showing photos from Unsplash given a keyword. I managed to fetch specific photos using unsplash.js. In my actions, I have several action creators:

export const fetchPhotos = () => ({
  type: FETCH_PHOTOS
});

export const receivePhotos = term => {
  const unsplash = new Unsplash({
    applicationId:
      "id",
    secret: "secret",
    callbackUrl: "callback"
  });
  console.log(term);

  const response = unsplash.search
    .photos(term, 1, 20)
    .then(toJson)
    .then(json => json)
    .then(json => json)

  console.log(response.then(results => results));
  return {
    type: RECEIVE_PHOTOS,
    payload: response
  };
}

export const unsplash = (term) => dispatch => {
  console.log(term);
  dispatch(fetchPhotos());

  setTimeout(() => {
    dispatch(receivePhotos(term));
    console.log("dispatching")
    return Promise.resolve();
  }, 1000)
}

My reducers then do:

const initialState = {
  isFetching: false,
  sortDirection: null,
  sortKey: null,
  items: []
}

export default function(state = initialState, action) {
  switch (action.type) {
    case FETCH_PHOTOS:
    console.log(state, "Fetch photos reducer");
      return {
        ...state,
        isFetching: true
      };
    case RECEIVE_PHOTOS:
      console.log("Receive photos reducer", action.payload)
      return {
        ...state,
        isFetching: false,
        items: action.payload
      };
    case SET_SORT:
      return {
        ...state,
        sortKey: action.sortKey,
        sortDirection: action.sortDirection
      };
    default:
      return state;
  }
}

However, as the receivePhotos action creator calls an API, I have a promise that needs to be resolved in order for the whole application to work. My fetch photos reducer is console logging the action, then the Promise appears, however it is always on pending. Then my receivePhotos action creator dispatches to the reducer and I can see that this is a Promise:

enter image description here

How can I resolve this promise?

1条回答
祖国的老花朵
2楼-- · 2019-08-21 07:57

In the below code you assign a promise to response, then console.log that promise, and then return the action with payload set to that promise.

const response = unsplash.search
  .photos(term, 1, 20)
  .then(toJson)
  .then(json => json)
  .then(json => json)

console.log(response.then(results => results));
return {
  type: RECEIVE_PHOTOS,
  payload: response
};

dispatch(receivePhotos(term)); then dispatches that action, still with the payload as a promise. maybe this would work if you had middleware that could handle it.

This use of dispatch suggests that you are using redux-thunk though. In that case, you should do the same with receivePhotos, include the fetchPhotos call, and retire the unsplash action.

const unsplashClient = new Unsplash({
  applicationId:
    "id",
  secret: "secret",
  callbackUrl: "callback"
});

export const receivePhotos = term => dispatch => {
  dispatch(fetchPhotos());
  return unsplashClient.search
    .photos(term, 1, 20)
    .then(toJson)
    .then(json => dispatch({
      type: RECEIVE_PHOTOS,
      payload: json
    });
}

In the end I would suggest a bit of refactoring of the actions and the (related reducers) such as:

const unsplashClient = new Unsplash({
  applicationId:
    "id",
  secret: "secret",
  callbackUrl: "callback"
});

export const fetchingPhotos = payload => ({
  type: FETCHING_PHOTOS, payload
});

export const setPhotos = payload => ({
  type: SET_PHOTOS, payload
});

export const fetchPhotos = term => dispatch => {
  dispatch(fetchingPhotos(true));
  return unsplashClient.search
    .photos(term, 1, 20)
    .then(toJson)
    .then(json => {
      dispatch(setPhotos(json));
      dispatch(fetchingPhotos(false));
    });
}
查看更多
登录 后发表回答