【问题标题】:takeSequential in redux-saga?在redux-saga中采取Sequential?
【发布时间】:2019-03-07 03:28:32
【问题描述】:

我有一个看起来像这样的基本传奇:

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

这搞砸了我的 reducer 中的逻辑。

我想要的是运行每个请求,但要等待前一个请求完成后再开始。

即。所以它看起来像:

SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS

我将如何实现这一目标?

【问题讨论】:

    标签: redux-saga


    【解决方案1】:

    actionChannel 效果可以用来实现这一点。

    见:https://redux-saga.js.org/docs/api/#actionchannelpattern-buffer

    const mySaga = function* () {
        const channel = yield actionChannel("SOME_ACTION_REQUEST"); 
        while (true) {
            const action = yield 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
    

    因为请求会立即添加到通道中,并且在它们被弹出之前保持非活动状态。

    【讨论】:

    • 应该使用yield来执行take,因为应该在while (true)循环中等待动作。
    【解决方案2】:

    您只需通过两个分叉任务即可实现此目的。就像一个乒乓消息系统。

    对于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),
      ]);
    }
    

    【讨论】:

    • 嗯。我喜欢它。
    • 您将丢失一些SOME_ACTION_REQUEST 操作,就在上一个操作完成之间。这就像takeLeading
    • @cyrilluce,不会的。这只会产生两个任务,而不是每次收到操作。
    • @codekaizer 在传奇ping 中,当使用SOME_ACTION_SUCCESS 时,它正在阻塞,如果另一个SOME_ACTION_REQUEST 被触发,它将丢失。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 2017-05-28
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-22
    相关资源
    最近更新 更多