在运行时动态添加史诗会多次调用新添加的史诗

时间:2017-10-20 18:04:21

标签: redux rxjs redux-observable

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

所以我遇到了这个测试来执行史诗的问题,我错过了什么吗?在任何情况下,代码都会解释发生了什么......

我希望我的store.dispatch({type:'GO'})号召连接我的所有史诗。我看到我的减速器接线了但Epics没有被调用。

fyi我需要这个来测试我认为是一个bug。在我的实际应用程序中,当我使用epicLoader$.next(<someepic>)动态加载一个新的史诗时,动态加载的史诗现在被调用两次......但是我无法证明这一点直到这个测试有效。

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

帮助我Obi wan ...

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'});
});

1 个答案:

答案 0 :(得分:1)

我想我看到提供的代码存在两个问题:

提供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吗?

image