我有以下用于调用类似异步调用的中间件:
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
中的原始调用中调用fetchResults
和componentWillMount
的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
函数吗?