javascript - 这可以重构为示例中更可组合的样式吗?
问题描述
我对 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);
});
});
}
解决方案
完全取决于您要执行的操作,但大致看起来应该类似于...
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
之间添加一个来实现。这将在一些小方面与您的代码不同,您可以根据需要进行调整。startWith
combineLatest
在您的示例中,如果initialData
很冷并且需要一段时间才能触发并且clickSource
更早触发,valueSource
那么您可以获得一个空数组。initialData
在我的示例中,在至少触发一次之前,您不会得到任何结果。如果你想要这种行为,你可以startWith
在data
之前使用。switchMap
此外,在您的示例中,如果initalData
再次触发,则不会发生任何事情(可观察对象将继续过滤旧的原始值),在此示例中,如果initialData
再次触发,则它将切换到过滤新数组,但可能会丢失来自valueSource
.
在您的示例中,您将不会得到任何结果,然后第一个结果将到达,如果其中之一clickSource
或valueSource
触发。我想不出一种方法来完全复制这个我的头顶。我的代码一旦data
触发就会立即触发一次。如果你关闭它startWith
,clicks
那么它只会在着火时clickSource
触发。如果你关闭它startWith
,value
那么它只会valueSource
在至少触发一次时触发。如果你真的需要这种行为,你可能会开始,而data.filter
不是merge(clicks, value).pipe(switchMap(_ => data.filter...