【问题标题】:Is it safe to call sagaMiddleware.run multiple times?多次调用 sagaMiddleware.run 是否安全?
【发布时间】:2018-09-14 02:29:55
【问题描述】:

我在应用程序中使用 redux 和 redux-saga 来管理状态和异步操作。为了让我的生活更轻松,我编写了一个基本上充当 saga 管理器的类,并带有一个“注册”saga 的方法。这个注册方法派生了新的 saga,并使用 redux-saga/effects/all 将它与所有其他注册的 saga 结合起来:

class SagasManager {
    public registerSaga = (saga: any) => {
        this._sagas.push(fork(saga));
        this._combined = all(this._sagas);
    }
}

然后我的商店使用这个类来获取_combined saga,据说在所有 saga 都注册之后:

const store = Redux.createStore(
    reducer, 
    initialState, 
    compose(Redux.applyMiddleware(sagaMiddleware, otherMiddleware)),
);
sagaMiddleware.run(sagasManager.getSaga());

但是,我遇到了一个问题,即根据情况(如导入顺序),这并不总是按预期工作。发生的事情是,在调用 sagaMiddleware.run 之前,一些 sagas 没有被注册。

我通过在SagasManager 上提供回调来解决这个问题:

class SagasManager {
    public registerSaga = (saga: any) => {
        this._sagas.push(fork(saga));
        this._combined = all(this._sagas);
        this.onSagaRegister();
    }
}

然后商店代码可以用这个作为

sagasManager.onSagaRegister = () => sagaMiddleware.run(sagasManager.getSaga());

这似乎有效,但我无法在文档中找到这是否安全。我确实看到.run 返回一个Task,它具有取消等方法,但由于我的问题只是在构建商店和呈现应用程序之间的那个尴尬时间,我不会那样做一个问题。

谁能解释这是否安全,如果不安全,还有什么更好的解决方案?

【问题讨论】:

    标签: javascript reactjs typescript redux redux-saga


    【解决方案1】:

    这可能取决于您所说的“安全”是什么意思。在这种情况下,你到底是什么意思?

    首先,这里是 source of runSaga itself,它被 saga 中间件使用。

    往里面看runSaga,我明白了:

    export function runSaga(options, saga, ...args) {
      const iterator = saga(...args)
    
      // skip a bunch of code
    
      const env = {
        stdChannel: channel,
        dispatch: wrapSagaDispatch(dispatch),
        getState,
        sagaMonitor,
        logError,
        onError,
        finalizeRunEffect,
      }
    
      const task = proc(env, iterator, context, effectId, getMetaInfo(saga), null)
    
      if (sagaMonitor) {
        sagaMonitor.effectResolved(effectId, task)
      }
    
      return task
    }
    

    我从中得到的是,当您致电 runSaga(mySagaFunction) 时,不会发生任何“破坏性”事情。但是,如果您多次使用相同的 saga 函数调用 runSaga(),那么您可能会运行该 saga 的多个副本,这可能会导致您的应用程序不想要的行为。

    您可能想尝试一下。例如,如果您有一个计数器应用程序并执行此操作会发生什么?

    function* doIncrement() {
        yield take("DO_INCREMENT");
        put({type : "INCREMENT"});
    }
    
    sagaMiddleware.runSaga(doIncrement);
    sagaMiddleware.runSaga(doIncrement);
    
    store.dispatch({type : "DO_INCREMENT"});
    
    console.log(store.getState().counter);
    // what's the value?
    

    我的猜测是计数器会是 2,因为 doIncrement 的两个副本都会响应。

    如果这种行为是一个问题,那么您可能希望确保取消之前的 sagas。

    实际上,我在不久前的热重载期间遇到了一个取消 sagas 的方法,included a version of that in a gist for my own usage。您可能想参考它以获取想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-18
      • 2018-09-20
      • 1970-01-01
      • 2014-06-15
      • 2012-07-09
      相关资源
      最近更新 更多