我有一个基本的传奇,看起来像这样:
const mySaga = function* () {
yield takeEvery("SOME_ACTION_REQUEST", function* (action) {
const result = yield call(makeApiCall, action.payload);
yield put({
type: "SOME_ACTION_SUCCESS",
payload: result
});
});
}
现在我遇到的问题是,如果我同时调度了两个"SOME_ACTION_REQUEST"
,那么我有一个redux调用堆栈的情况:
SOME_ACTION_REQUEST
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_SUCCESS
而这正在削弱我的减速机中的逻辑。
我想要的是,每个请求都要运行,但是它要等待前一个请求在启动之前完成。
即。所以它看起来像:
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
我怎么做到这一点?
actionChannel
效应可用于实现这一目标。
见:https://redux-saga.js.org/docs/api/#actionchannelpattern-buffer
const mySaga = function* () {
const channel = yield actionChannel("SOME_ACTION_REQUEST");
while (true) {
const action = take(channel);
const result = yield call(makeApiCall, action.payload);
yield put({
type: "SOME_ACTION_SUCCESS",
payload: result
});
}
}
说明:
我的理解是actionChannel
效果只是将匹配该模式的所有传入请求路由到队列中。
take
效应会让它们脱落。
将它全部放在while(true)
循环中意味着一次一个地弹出一个动作,并且它们需要等待在下一个动作被调用之前解决所有其他事情(API调用)。
关于这种模式需要注意的一点是,在redux-dev-tools中,redux堆栈仍然看起来像:
SOME_ACTION_REQUEST
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_SUCCESS
因为请求会立即添加到频道并保持不活动状态,直到它们被弹出为止。
只需两个分叉任务即可实现此目的。就像一个乒乓消息系统。
对于takeEvery
,始终为收到的每个操作创建一个新的分叉任务。
像这样的东西:
function* ping() {
while (true) {
const { payload } = yield take("SOME_ACTION_REQUEST");
yield put({
type: "DO_REQUEST",
payload
});
yield take("SOME_ACTION_SUCCESS");
}
}
function* pong() {
while (true) {
const { payload } = yield take("DO_REQUEST");
const result = yield call(makeApiCall, payload);
yield put({
type: "SOME_ACTION_SUCCESS",
payload: result
});
}
}
function* rootSaga() {
yield all([
fork(ping),
fork(pong),
]);
}