【问题标题】:Blocking takeEvery with redux saga使用 redux saga 阻止 takeEvery
【发布时间】:2023-11-13 20:13:01
【问题描述】:

我希望能够通过 redux 从应用程序的不同部分调用两组操作。但是,我想以正确的顺序运行它们,并确保 set b 永远不会在 set a 之前运行。

例如,假设我有两个操作,configureexecute。我需要确保execute 永远不会在configure 之前运行,但它们可能会被乱序调度。在这种情况下,我需要将 execute 加入队列,并且仅在 configure 完成后处理。

这可以在 redux-saga 中做到吗?

我尝试了以下方法,似乎根本没有阻塞:

function* configureSaga({ payload }): IterableIterator<any> {
  yield put(aFirstThing(payload));
  yield put(aSecondThing());
}

function* executeSaga({ payload }): IterableIterator<any> {
  yield put(aThirdThing(payload));
  yield put(aFourthThing());
}

export function* adsSaga(): IterableIterator<any> {
  const configureChanel = yield actionChannel({ type: 'configure' });
  yield takeEvery(configureChanel, configureSaga);
  yield takeEvery({ type: 'execute' }), executeSaga);
}

按照以下顺序给定两个调度:

dispatch({ type: 'execute' })
dispatch({ type: 'configure' })

我需要按该顺序执行的aFirstThing, aSecondThing, aThirdThing, aFourthThing 操作。

redux-sagas 可以做到这一点吗?

【问题讨论】:

    标签: reactjs redux react-redux redux-saga


    【解决方案1】:

    takeEvery 对于最常见的情况很有用,但对于更复杂的情况,您通常会改为编写自定义循环。根据您希望如何处理在配置/执行期间分派的额外操作,实现会有所不同。

    忽略所有其他配置/执行操作(等待第二个操作时)+ 忽略所有操作,直到配置完成:

    export function* adsSaga() {
      while (true) {
        const [executePayload, configurePayload] = yield all([
          take('configure'),
          take('execute'),
        ])
        yield call(configureSaga, configurePayload);
        yield fork(executeSaga, executePayload);
      }
    }
    

    忽略所有额外的配置/执行操作(等待第二个操作时)+ 缓冲所有操作直到配置完成:

    export function* rootSaga() {
      const configureChan = yield actionChannel('configure');
      const executeChan = yield actionChannel('execute');
      while (true) {
        const [executePayload, configurePayload] = yield all([
          take(configureChan),
          take(executeChan),
        ])
        yield call(configureSaga, configurePayload);
        yield fork(executeSaga, executePayload);
      }
    }
    

    要使配置+执行操作等待每个其他人,您可以使用 all+take 的组合。仅当您要处理配置+执行组合的多“轮”时才需要 actionChannel。

    您可以将这些解决方案修改为例如仅缓冲配置或执行操作。或者,如果您想在配置和执行完成之前忽略所有操作,请使用 call 而不是 fork 来运行 executeSaga。您还可以通过将call+fork 效果放在另一个分叉传奇中来允许同时运行多个配置。如果您愿意,还可以选择将自定义缓冲区传递给操作通道,例如一次最多缓冲一个动作。

    【讨论】:

    • 你能解释一下这是如何工作的吗?我看不到执行动作触发,如果我把调试器语句放进去,我看不到在call 语句之后运行任何东西。我的理解是take 正在阻塞,所以这是否意味着如果executeconfigure 之前调度,第二个take 将永远不会运行?
    • 抱歉,我主要关注的是您可以编写一个自定义循环来处理这个问题,并没有考虑太多关于排队操作,我更新了我的答案。