作为世界上应用程序的必备品,我的React应用程序需要对API执行一些Ajax调用 .
我选择使用Redux中间件来正确地将API提取与我的组件分开 .
我的想法是从我的组件发送 REQUEST
动作 . 中间件监听它们并发送 SUCCESS
或 ERROR
动作:这些动作最后由reducers监听 .
这里有很多人已经问过如何从Redux中间件调度操作:这是我在这里问题的主题:)
首先,让我向您展示一个我用来编写的简单减速器:
function currentUserReduxer(state = {}, action = {}) {
const { currentUser, error } = action.payload;
switch (action.type) {
case 'GET_CURRENT_USER_REQUEST':
return { ...state, isFetching: true, error: null };
case 'GET_CURRENT_USER_SUCCESS':
return { ...state, id: currentUser.id, isFetching: false };
case 'GET_CURRENT_USER_FAILURE':
return { ...state, isFetching: false, error };
default:
return state;
}
}
和相应的中间件:
() => next => async (action) => {
next(action);
switch (action.type) {
case'GET_CURRENT_USER_REQUEST': {
try {
const currentUser = await api.getCurrentUser();
next(actions.getCurrentUserSuccess(currentUser));
} catch (error) {
next(actions.getCurrentUserFailure(error));
}
break;
}
default:
break;
}
};
它很长时间以来运行良好,然后我意识到它部分错误:我的中间件没有返回 next
的值,所以它打破了中间件链,这是错误的!
由于 next(action);
是我've performed in the middleware, I couldn'牛逼很快回到它本的第一件事,所以我've moved it at the end of the middleware. I'以前也决定派遣新的行动,而不是使用 next
他们(毕竟,他们是新的行动,这有一定道理送他们到整个产业链中间件) . 我的新中间件现在看起来像这样:
store => next => async (action) => {
switch (action.type) {
case'GET_CURRENT_USER_REQUEST': {
try {
const currentUser = await api.getCurrentUser();
store.dispatch(actions.getCurrentUserSuccess(currentUser));
} catch (error) {
store.dispatch(actions.getCurrentUserFailure(error));
}
break;
}
default:
break;
}
return next(action);
};
它看起来很棒,但我现在有另一个问题:因为 store.dispatch
是同步的,所以 next(action)
被调用 . That means that my reducers receive the REQUEST action AFTER the SUCCESS or FAILURE ones :(
我认为一个解决方案可能是使用旧的承诺而不是 await
:
store => next => async (action) => {
switch (action.type) {
case'GET_CURRENT_USER_REQUEST': {
api.getCurrentUser()
.then((currentUser) => {
store.dispatch(actions.getCurrentUserSuccess(currentUser));
})
.catch((error) => {
store.dispatch(actions.getCurrentUserFailure(error));
});
break;
}
default:
break;
}
return next(action);
};
另一个想法是用 setTimeout
包装 store.dispatch
:
store => next => async (action) => {
switch (action.type) {
case'GET_CURRENT_USER_REQUEST': {
try {
const currentUser = await api.getCurrentUser();
setTimeout(() => store.dispatch(actions.getCurrentUserSuccess(currentUser)));
} catch (error) {
setTimeout(() => store.dispatch(actions.getCurrentUserFailure(error)));
}
break;
}
default:
break;
}
return next(action);
};
说实话,我真的不喜欢这两种解决方案,他们觉得这么hacky ......
所以这是我的问题:我怎么想处理我的问题?有更干净的方法吗?
提前致谢 :)
1 回答
好像你想要做的事情类似于Redux-Saga我建议你去看看他们的图书馆 .
取自他们的榜样