微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 switchMap

如何解决在 switchMap

假设您有一个函数返回一个包含对象列表的 rxjs observable。

const getItems = () =>
  of([
    {
      id: 1,value: 10
    },{
      id: 2,value: 20
    },{
      id: 3,value: 30
    }
  ]);

和第二个函数返回一个带有单个对象的 observable

const getItem = id =>
  of({
    id,value: Math.floor(Math.random() * 30) + 1
  });

现在我们要创建一个 observable,它将获取一个列表,并定期随机更新任何列表项。

const source = getItems().pipe(
  switchMap(items =>
    interval(5000).pipe(
      switchMap(x => {
        // pick up a random id
        const rId = Math.floor(Math.random() * 3) + 1;

        return getItem(rId).pipe(
          map(item =>
            items.reduce(
              (acc,cur) =>
                cur.id === item.id ? [...acc,item] : [...acc,cur],[]
            )
          )
        );
      })
    )
  )
);

source.subscribe(x => console.log(JSON.stringify(x)));

上述代码的问题在于,每次触发间隔时,上一次迭代中的项目都会重置为其初始形式。例如,

[{"id":1,"value":10},{"id":2,"value":13},{"id":3,"value":30}]
[{"id":1,"value":20},"value":18}]
[{"id":1,"value":16},"value":21},"value":30}]

如您所见,我们的代码在每个时间间隔都会重置列表并更新一个新项目(例如,值 13 在第二次迭代中丢失并恢复为 20)。 这种行为似乎是合理的,因为第一个 items 中的 switchMap 参数就像一个闭包。

我设法通过使用 BehaviorSubject 以某种方式解决了这个问题,但我认为我的解决方案有点脏。

const items$ = new BehaviorSubject([]);

const source = getItems().pipe(
  tap(items => items$.next(items)),switchMap(() =>
    interval(5000).pipe(
      switchMap(() => {
        const rId = Math.floor(Math.random() * 3) + 1;

        return getItem(rId).pipe(
          map(item =>
            items$
              .getValue()
              .reduce(
                (acc,cur) =>
                  cur.id === item.id ? [...acc,[]
              )
          ),tap(items => items$.next(items)),switchMap(() => items$)
        );
      })
    )
  )
);

有更好的方法吗?

示例代码here

解决方法

我相信这应该是你想要的:

const source = getItems().pipe(
  switchMap(items =>
    interval(1000).pipe(
      switchMap(() => {
        const rId = Math.floor(Math.random() * 3) + 1;
        return getItem(rId);
      }),scan((acc,item) => {
        acc[acc.findIndex(i => i.id === item.id)] = item;
        return acc;
      },items),)
  )
);

这基本上就是你在做什么,但我使用 scan(用原始 items 初始化)将输出数组保存在 acc 中,以便我稍后更新它再次。

现场演示:https://stackblitz.com/edit/rxjs-kvygy1?file=index.ts

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。