正确的方法来清除redux中间件中的异步工作

时间:2016-11-13 20:48:43

标签: promise redux es6-promise

我有以下用于调用类似异步调用的中间件:

import { callApi } from '../utils/Api';

import generateUUID from '../utils/UUID';

import { assign } from 'lodash';

export const CALL_API = Symbol('Call API');

export default store => next => action => {
  const callAsync = action[CALL_API];

  if(typeof callAsync === 'undefined') {
    return next(action);
  }

  const { endpoint, types, data, authentication, method, authenticated } = callAsync;

  if (!types.REQUEST || !types.SUCCESS || !types.FAILURE) {
    throw new Error('types must be an object with REQUEST, SUCCESS and FAILURE');
  }

  function actionWith(data) {
    const finalAction = assign({}, action, data);
    delete finalAction[CALL_API];

    return finalAction;
  }

  next(actionWith({ type: types.REQUEST }));

  return callApi(endpoint, method, data, authenticated).then(response => {
    return next(actionWith({
      type: types.SUCCESS,
      payload: {
        response
      }
    }))
  }).catch(error => {
    return next(actionWith({
      type: types.FAILURE,
      error: true,
      payload: {
        error: error,
        id: generateUUID()
      }
    }))
  });
};

然后我在组件componentWillMount中进行以下调用:

  componentWillMount() {
    this.props.fetchResults();
    this.props.fetchTeams();
  }
例如,

fetchTeams将调度由中间件处理的操作,如下所示:

export function fetchTeams() {
  return (dispatch, getState) => {
    return dispatch({
      type: 'CALL_API',
      [CALL_API]: {
        types: TEAMS,
        endpoint: '/admin/teams',
        method: 'GET',
        authenticated: true
      }
    });
  };
}

调度成功操作并从reducer返回新状态。两个Reducer看起来都一样,下面是Teams reducer:

export const initialState = Map({
  isFetching: false,
  teams: List()
});

export default createReducer(initialState, {
  [ActionTypes.TEAMS.REQUEST]: (state, action) => {
    return state.merge({isFetching: true});
  },

  [ActionTypes.TEAMS.SUCCESS]: (state, action) => {
    return state.merge({
      isFetching: false,
      teams: action.payload.response
    });
  },

  [ActionTypes.TEAMS.FAILURE]: (state, action) => {
    return state.merge({isFetching: false});
  }
});

然后该组件呈现另一个分派另一个动作的组件:

render() {
  <div>
   <Autocomplete items={teams}/>
  </div>
}

自动填充然后在componentWillMount

中调度操作
class Autocomplete extends Component{
  componentWillMount() {
    this.props.dispatch(actions.init({ props: this.exportProps() }));
  }

如果在从父组件的fetchTeams中的原始调用中调用fetchResultscomponentWillMount的SUCCESS Reducer之后调用的autocomplete reducer中发生错误,则会发生错误将在中间件中发生的Promise.catch方法的callApi中处理。

return callApi(endpoint, method, data, authenticated).then(response => { return next(actionWith({ type: types.SUCCESS, payload: { response } })) }).catch(error => { return next(actionWith({ type: types.FAILURE, error: true, payload: { error: error, id: generateUUID() } })) }); };

这是因为它发生在事件循环的相同刻度中。如果我在Autcomplete componentWIllMount函数中引入一些异步性,那么错误不会在中间件的Promise catch处理程序中处理

class Autocomplete extends Component{ componentWillMount() { setTimeout(() => { this.props.dispatch(actions.init({ props: this.exportProps() })); }); } 我应该在单独的事件循环中执行callApi函数吗?

0 个答案:

没有答案