代码之家  ›  专栏  ›  技术社区  ›  bheklilr

打电话安全吗sagaMiddleware.run多次?

  •  2
  • bheklilr  · 技术社区  · 6 年前

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

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

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

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

    但是,我遇到了一个问题,即根据具体情况(如进口订单),这并不总是按预期工作。所发生的事情是,一些传奇故事没有得到登记之前,呼吁 sagaMiddleware.run .

    我通过回拨 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 ,它有取消等方法,但由于我的问题只是在构建存储和呈现应用程序之间的尴尬时间,所以我不认为这是个问题。

    1 回复  |  直到 6 年前
        1
  •  1
  •   markerikson    6 年前

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

    首先,这里是 source of runSaga itself 以及saga中间件在哪里使用它。

    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) . 但是,如果你打电话 runSaga() 使用同一个saga函数多次,您可能会运行该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 会有反应的。

    如果这种行为是一个问题,那么你可能想确保之前的传奇故事被取消。

    事实上,我偶然发现了一个配方取消传奇热重新加载一段时间,和 included a version of that in a gist for my own usage . 你可能想参考一下。