首页 > 解决方案 > 这可以重构为示例中更可组合的样式吗?

问题描述

我对 rxjs 很陌生,我想出的这个例子并不那么优雅。本质上,我怎样才能将 3 个截然不同的可观察对象组合成一个?你真的可以像许多在线示例那样以高阶函数的方式来做吗?

createFilteredDataObservable(initialData: Observable<Data[]>,
                             valueSource: Observable<any>, 
                             clickSource: Subject<boolean>): Observable<Data[]> {
    let data: Data[] = [];
    let text = '';

    initialData.subscribe(value => {
      data= value;
    });

    function format(x: string): string {
      return x.toLowerCase().trim();
    }

    function filter() {
      if (text === '') {
        return data;
      }

      const result = data.filter(d=> {
        const name = format(d.DisplayName);
        return name === text || name.includes(text);
      });

      return result;
    }

    return new Observable<Data[]>((observer) => {

      clickSource.subscribe(_ => {
        const result = filter();
        observer.next(result);
      });

      valueSource.subscribe((v: string|Data) => {
        if (typeof v !== 'string') {
          return;
        }
        text = format(v);
        const result = filter();
        observer.next(result);
      });

    });
}

标签: javascripttypescriptrxjs

解决方案


完全取决于您要执行的操作,但大致看起来应该类似于...

const filtered = data.pipe(switchMap(data => {
  return value.pipe(startWith(''), combineLatest(clicks.pipe(startWith(null))), map(([value, _]) => {
    return data.filter(item => item.includes(value));
  }));
}));

这是您可以玩的要点:https ://gist.github.com/westonpace/4f7811b6735c94e97928be1bb6a377ce

为简洁起见,我省略了format和简化filter,但这可以通过map在和value之间添加一个来实现。这将在一些小方面与您的代码不同,您可以根据需要进行调整。startWithcombineLatest

在您的示例中,如果initialData很冷并且需要一段时间才能触发并且clickSource更早触发,valueSource那么您可以获得一个空数组。initialData在我的示例中,在至少触发一次之前,您不会得到任何结果。如果你想要这种行为,你可以startWithdata之前使用。switchMap

此外,在您的示例中,如果initalData再次触发,则不会发生任何事情(可观察对象将继续过滤旧的原始值),在此示例中,如果initialData再次触发,则它将切换到过滤新数组,但可能会丢失来自valueSource.

在您的示例中,您将不会得到任何结果,然后第一个结果将到达,如果其中之一clickSourcevalueSource触发。我想不出一种方法来完全复制这个我的头顶。我的代码一旦data触发就会立即触发一次。如果你关闭它startWithclicks那么它只会在着火时clickSource触发。如果你关闭它startWithvalue那么它只会valueSource在至少触发一次时触发。如果你真的需要这种行为,你可能会开始,而data.filter不是merge(clicks, value).pipe(switchMap(_ => data.filter...


推荐阅读