Redux-thunk:API 响应保持挂起

问题描述:

我正在尝试开发一个应用程序,该应用程序在给定关键字的情况下显示来自 Unsplash 的照片.我设法使用 unsplash.js 获取特定照片.在我的行动中,我有几个行动创建者:

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)
}

我的减速器然后做:

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;
  }
}

但是,当 receivePhotos 操作创建者调用 API 时,我有一个需要解决的承诺,以便整个应用程序正常工作.我的获取照片减速器正在控制台记录操作,然后出现 Promise,但它始终处于挂起状态.然后我的 receivePhotos 动作创建者分派给 reducer,我可以看到这是一个 Promise:

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:

我该如何兑现这个承诺?

How can I resolve this promise?

在下面的代码中,您将承诺分配给 response,然后 console.log 该承诺,以及然后返回将 payload 设置为该承诺的操作.

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)); 然后分派那个动作,仍然以有效载荷作为承诺.也许如果您有可以处理它的中间件,这会起作用.

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.

这种调度的使用表明您正在使用 redux-thunk.在这种情况下,您应该对 receivePhotos 执行相同的操作,包括 fetchPhotos 调用,并退出 unsplash 操作.

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));
    });
}