在运行时动态添加 epics 多次调用新添加的 epics

Dynamically adding epics during runtime calls the newly added epics multiple times

我的工作基于这些方向:https://redux-observable.js.org/docs/recipes/AddingNewEpicsAsynchronously.html

所以我在让这个测试执行 epics 时遇到问题,我是不是遗漏了什么?在任何情况下,代码都会解释发生了什么......

我希望我对 store.dispatch({type:'GO'}) 的调用能够链接我所有的 epics。我看到我的减速器已连接,但 Epics 没有被调用。

fyi 我需要这个来测试我认为是错误的东西。在我的实际应用程序中,当我使用 epicLoader$.next(<someepic>) 动态加载新的史诗时,动态加载的史诗现在被调用了两次......但在这个测试起作用之前我无法证明这一点。

作为解决方法,我手动添加了我想动态添加的 epics,它工作正常,但在我的 POC 阶段这是不可能的。我需要从将被推送到应用程序的单独文件中加载 epics。

帮我欧比万...

import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/mapTo';
import 'rxjs/add/operator/do';
import { Observable } from 'rxjs/Observable';

import {combineReducers, createStore, applyMiddleware} from 'redux';
import { createEpicMiddleware,combineEpics } from 'redux-observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

test('dynamicly loading epic calls it twice',done => {
  let epic1 = (action$)=>action$
    .ofType('GO')
    .do((action)=>console.log('epic1',action))
    .mapTo({type:'EPIC1'});

  let epic2 = (action$,{epicLoader$})=>action$
    .ofType('EPIC1')
    .do((action)=>console.log('epic2',action))
    .do(()=>epicLoader$.next(epic3))
    .do(()=>epicLoader$.next(epic4))
    .mapTo({type:'EPIC2'});

  let epic3 = (action$)=>action$
    .ofType('EPIC2')
    .do((action)=>console.log('epic3',action))
    .mapTo({type:'EPIC3'});

  let epic4 = (action$)=>action$
    .ofType('EPIC2')
    .do((action)=>console.log('epic4',action))
    .do(()=>done())
    .mapTo({type:'EPIC4'});


  const epic$ = new BehaviorSubject(combineEpics({epic1,epic2}));
  const rootEpic = (action$, store, args) =>
    epic$.mergeMap(epic =>
      epic(action$, store, args)
    );

  const epicMiddleware = createEpicMiddleware(rootEpic,
    { dependencies: {
      epicLoader$: epic$,
    }});

  const reducer =(state = {},action)=>{
    console.log('reducer',action);
    return state;
   };

  const store = createStore(
    combineReducers({
      reducer
    }),
    applyMiddleware(epicMiddleware)
  );
  //start up the chain of events.
  store.dispatch({type:'GO'});
});

我认为所提供的代码存在两个问题:

combineEpics 提供对象,而不仅仅是参数

您正在将一个对象传递给 combineEpics,但它应该只是普通的旧参数。这不同于 combineReducers

// bad
const epic$ = new BehaviorSubject(combineEpics({epic1,epic2}));
// good
const epic$ = new BehaviorSubject(combineEpics(epic1,epic2));

此处讨论了对传递对象的支持:https://github.com/redux-observable/redux-observable/issues/58。它还没有被支持,因为键是没有意义的,不像 combineReducers.

当订阅 rootEpic 时,这确实会抛出一个错误,但不幸的是,由于 outstanding bug in rxjs

解构 store 而不是第三个依赖项参数

// bad
let epic2 = (action$,{epicLoader$})=>action$
// good
let epic2 = (action$,store,{epicLoader$})=>action$

修复这些后,它似乎可以正常工作:

我确实注意到 epic4 正在监听 EPIC2,您可能实际上是想监听 EPIC3