不应该调用 RxJS iif 参数

Posted

技术标签:

【中文标题】不应该调用 RxJS iif 参数【英文标题】:RxJS iif arguments are called when shouldn't 【发布时间】:2019-06-03 12:14:20 【问题描述】:

我想使用 RxJS 中的 iif 实用程序有条件地调度一些操作。问题是即使测试函数返回 false,也会调用 iif 的第二个参数。这会引发错误,并且应用程序会立即崩溃。我对 RxJS 的力量很陌生,所以我可能不知道一些事情。如果这很重要,我正在使用 connected-react-router 包。

export const roomRouteEpic: Epic = (action$, state$) => action$.ofType(LOCATION_CHANGE).pipe( 采摘('有效载荷'), 合并地图(有效载荷 => iif( () => console.log('未记录'); 返回 /^\/room\/\d+$/.test(payload.location.pathname); // 设置为“/登录” , 合并( tap(v => console.log('NOT LOGGED TOO')), 的( // 立即评估以下状态值 state$.value.rooms.list[payload.location.pathname.split('/')[1]] ? actions.rooms.initRoomEnter() :actions.rooms.initRoomCreate(), ), of(actions.global.setIsLoading(true)), ), 空的(), ), ), );

【问题讨论】:

iif 的第二个参数应该在测试函数返回 false 时被调用。如果测试函数返回true,将调用第一个参数。请参阅文档here 通过第一个参数我计算测试函数。第二个和第三个在测试后调用。 好的,感谢您的澄清。接下来,再次检查测试函数是否实际返回true。如果它返回除此之外的任何内容,则iif 会将其评估为false。我会尝试用() => true 替换您当前拥有的东西,看看它是否确实是导致问题的iif,或者您的测试逻辑。 【参考方案1】:

聚会晚了一点,但我发现iif 的角色不是执行一条路径而不是另一条路径,而是订阅一个 Observable或其他。也就是说,它将执行获取每个 Observable 所需的所有代码路径。

从这个例子...

import  iif, of, pipe  from 'rxjs';
import  mergeMap  from 'rxjs/operators';

const source$ = of('Hello');
const obsOne$ = (x) => console.log(`$x World`); return of('One');
const obsTwo$ = (x) => console.log(`$x, Goodbye`); return of('Two');

source$.pipe(
  mergeMap(v =>
    iif(
      () => v === 'Hello',
      obsOne$(v),
      obsTwo$(v)
    ))
).subscribe(console.log);

你会得到以下输出

Hello World
Hello, Goodbye
One

这是因为,为了得到obsOne$,它需要打印Hello WorldobsTwo$ 也是如此(除了路径打印 Hello, Goodbye)。

但是您会注意到它只打印One 而不是Two。这是因为iif 评估为true,因此订阅了obsOne$

虽然您的三元有效 - 我发现这篇文章解释了一种更加 RxJS 驱动的方式来很好地实现您想要的结果:https://rangle.io/blog/rxjs-where-is-the-if-else-operator/

【讨论】:

iif()执行的很好解释。 很好的解释!使用defer 可以解决这个问题。因此,如果您执行iif( condition, defer(() => obsOne$), defer(() => obsTwo$)),则只会执行与条件相对应的路径。【参考方案2】:

好的,我自己找到了答案。我的解决方案是完全删除 iif 并仅依赖 mergeMap 中的三元运算符。这样它就不会在每个“LOCATION_CHANGE”之后进行评估,并且只要 regExp 返回 true。感谢您的关注。

export const roomRouteEpic: Epic = (action$, state$) =>
  action$.ofType(LOCATION_CHANGE).pipe(
    pluck<any, any>('payload'),
    mergeMap(payload =>
      /^\/room\/\d+$/.test(payload.location.pathname)
        ? of(
            state$.value.rooms.list[payload.location.pathname.split('/')[2]]
              ? actions.rooms.initRoomEnter()
              : actions.rooms.initRoomCreate(),
            actions.global.setIsLoading(true),
          )
        : EMPTY,
    ),
  );

【讨论】:

【参考方案3】:

如果在 observable 创建中使用 tap 操作符(因为它返回 void),会导致如下错误

Error: You provided 'function tapOperatorFunction(source) 
return source.lift(new DoOperator(nextOrObserver, error, complete));
' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

移除水龙头并将控制台放入 subscribe() 中。

我创建了一个stackblitz demo。

【讨论】:

以上是关于不应该调用 RxJS iif 参数的主要内容,如果未能解决你的问题,请参考以下文章

查询错误中的 VBA 评估 IIF 的错误部分

Iif 在 C# 中等效

不推荐使用 Rxjs toPromise()

如何从 rxjs 6 withLatestFrom 键入数组映射参数

将订阅响应作为参数发送到方法 Angular/rxJs

RxJs javascript - bindNodeCallback和一个需要输入参数的Object方法函数