当使用redux observable时,从单个操作和单个流,我如何基于过滤器分派不同的操作 更新

当使用redux observable时,从单个操作和单个流,我如何基于过滤器分派不同的操作 更新,redux,rxjs,observable,redux-observable,Redux,Rxjs,Observable,Redux Observable,下面是一个使用redux observable的工作示例。这通过使用mergeMap和if/else语句实现了我想要的功能,但我希望使用Observable.filter,因为这看起来更优雅 原始问题 我有一个epic,它目前只发送一个动作,但希望基于使用单个流的过滤器发送不同的动作。以下是当前代码: const streamEpic = (action$) => action$.pipe( ofType('START_PLAYBACK_STREAM'), switchM

下面是一个使用redux observable的工作示例。这通过使用mergeMap和if/else语句实现了我想要的功能,但我希望使用
Observable.filter
,因为这看起来更优雅


原始问题 我有一个epic,它目前只发送一个动作,但希望基于使用单个流的过滤器发送不同的动作。以下是当前代码:

const streamEpic = (action$) => action$.pipe(
    ofType('START_PLAYBACK_STREAM'),
    switchMap(playbackStream$),
    filter((playEvent) => playEvent.type === 'LOAD')),
    map((playEvent) => loadActionCreator(playEvent.fileName))
    // how can I filter on other types? 
    // and dispatch other actions?
);
我见过许多rxjs示例,它们使用单个流和过滤器映射不同的操作,例如:

playbackStream$
    .filter((playEvent) => playEvent.type === 'LOAD'))
    .map((playEvent) => loadActionCreator(playEvent.fileName));

playbackStream$
    .filter((playEvent) => playEvent.type === 'START'))
    .map((playEvent) => startActionCreator());

playbackStream$
    .filter((playEvent) => playEvent.type === 'STOP'))
    .map((playEvent) => stopActionCreator());
我试图在redux observable中做同样的事情,但没有运气。如果我使用tap、ignoreElements和store.dispatch,我可以使以下内容正常工作,但我知道这是一种反模式

const streamLoadEvents = (action$, store) => action$.pipe(
    ofType('START_PLAYBACK_STREAM'),
    tap(() => {
        playbackStream$
            .filter((playEvent) => playEvent.type === 'LOAD'))
            .map((playEvent) => store.dispatch(loadActionCreator(playEvent.fileName)));

        playbackStream$
            .filter((playEvent) => playEvent.type === 'START'))
            .map((playEvent) => store.dispatch(startActionCreator()));

        playbackStream$
            .filter((playEvent) => playEvent.type === 'STOP'))
            .map((playEvent) => store.dispatch(stopActionCreator()));
    }),
    ignoreElements()
);
我知道我也可以在map或switchMap中使用switch或if/else语句,比如这里的答案:,但我想避免这样做,因为它相当不雅观,并且没有充分利用流媒体运营商。这里的答案是:似乎让我更接近


这里建议的方法是什么?您能给我指的是运算符还是示例?谢谢

你是对的,如果/否则只能作为最后的手段使用,那么你可能有几种方法来解决这个问题,无论如何,我的看法如下:

有一种方法可以被视为if/else操作符的反应等价物:你为它提供可观测值,如果其中任何一个发出,结果可观测值也会发出它自己的值(AC)。当一个新动作出现时,我们检查它,并相应地选择一个新动作创建者(AC)。让我们看一些代码:

  const filteredAction$ = action$.pipe(
      ofType('START_PLAYBACK_STREAM'),
  );
这里没什么有趣的,只是过滤掉我们不感兴趣的动作类型,然后

  const operation$ = merge(
      filteredAction$.pipe(
          filter((action) => action.payload.type === 'LOAD'),
          mapTo(loadActionCreator),
      ),
      filteredAction$.pipe(
          filter((action) => action.payload.type === 'START'),
          mapTo(startActionCreator),
      ),
      filteredAction$.pipe(
          filter((action) => action.payload.type === 'STOP'),
          mapTo(stopActionCreator),
      ),
  ).pipe(
      startWith(startActionCreator)
  );
在这里,我们根据动作的有效载荷选择要使用的动作创建者(请注意,我正在遵循-动作的数据现在在有效载荷属性下,有一个很棒的工具可以用作它的助手。此外,您可能应该重命名“type”道具以避免混淆)

基本上告诉$stream操作要发出什么,您可以将此表达式视为将函数分配给某个变量以供以后使用。每次调用史诗时,我们都会在这里为它选择一个合适的动作创建者。 这里实际上不需要(假设第一个操作始终包括 “开始”类型),仅用于语义目的

最后但并非最不重要的一点是,epic必须返回至少一个用于调度的操作:

return combineLatest(
      operation$,
      filteredAction$
  )
      .pipe(
          map((arg) => {
            const operation = arg[0];
            const actionObject = arg[1];
            return operation(actionObject);
          })
      )

两个流中的最新值组合在一起,形成一个后续操作:operation$(它为我们提供了一个合适的action creator函数)和filteredAction$(始终包含操作本身,我们可能需要从中获取一些数据)。

这里的答案有什么问题?我认为它准确地描述了你需要的东西。也许,但我不能让我的例子使用那个参考来工作。我能得到的最接近的方法是使用mergeMap和if/else,这两种方法很好用——我只是希望使用
Observable.filter
,因为它看起来更优雅。以下是一个游乐场,其中有一个工作示例: