Rit*_*hie 10 javascript rxjs typescript angular rxjs-pipeable-operators
我有一个组件,它onScrollEnd
在呈现虚拟列表中的最后一个项目时触发一个事件。此事件将执行新的 API 请求以获取下一页并使用scan
运算符将它们与先前的结果合并。
该组件还有一个触发onSearch
事件的搜索字段。
如何在scan
触发搜索事件时清除操作员之前的累积结果?或者我需要在这里重构我的逻辑吗?
const loading$ = new BehaviorSubject(false);
const offset$ = new BehaviorSubject(0);
const search$ = new BehaviorSubject(null);
const options$: Observable<any[]> = merge(offset$, search$).pipe(
// 1. Start the loading indicator.
tap(() => loading$.next(true)),
// 2. Fetch new items based on the offset.
switchMap(([offset, searchterm]) => userService.getUsers(offset, searchterm)),
// 3. Stop the loading indicator.
tap(() => loading$.next(false)),
// 4. Complete the Observable when there is no 'next' link.
takeWhile((response) => response.links.next),
// 5. Map the response.
map(({ data }) =>
data.map((user) => ({
label: user.name,
value: user.id
}))
),
// 6. Accumulate the new options with the previous options.
scan((acc, curr) => {
// TODO: Dont merge on search$.next
return [...acc, ...curr]);
}
);
// Fetch next page
onScrollEnd: (offset: number) => offset$.next(offset);
// Fetch search results
onSearch: (term) => {
search$.next(term);
};
Run Code Online (Sandbox Code Playgroud)
Jon*_*wag 12
要操纵 astate
的 ,scan
您可以编写高阶函数来获取旧状态和新更新。然后与合并运算符组合。这样您就可以坚持使用干净的面向流的解决方案,而不会产生任何副作用。
const { Subject, merge } = rxjs;
const { scan, map } = rxjs.operators;
add$ = new Subject();
clear$ = new Subject();
add = (value) => (state) => [...state, value];
clear = () => (state) => [];
const result$ = merge(
add$.pipe(map(add)),
clear$.pipe(map(clear))
).pipe(
scan((state, innerFn) => innerFn(state), [])
)
result$.subscribe(result => console.log(...result))
add$.next(1)
add$.next(2)
clear$.next()
add$.next(3)
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
Run Code Online (Sandbox Code Playgroud)
该方法可以轻松扩展和/或适应state
rxjs 中的其他用例。
示例(删除最后一项)
removeLast$ = new Subject()
removeLast = () => (state) => state.slice(0, -1);
merge(
..
removeLast$.pipe(map(removeLast)),
..
)
Run Code Online (Sandbox Code Playgroud)
我认为你可以通过重组你的链来实现你想要的(为了简单起见,我省略了tap
触发加载的调用):
search$.pipe(
switchMap(searchterm =>
concat(
userService.getUsers(0, searchterm),
offset$.pipe(concatMap(offset => userService.getUsers(offset, searchterm)))),
).pipe(
map(({ data }) => data.map((user) => ({
label: user.name,
value: user.id
}))),
scan((acc, curr) => [...acc, ...curr], []),
),
),
);
Run Code Online (Sandbox Code Playgroud)
每次发射search$
都会创建一个新的内部 Observable ,它有自己的,并且scan
从一个空的累加器开始。
归档时间: |
|
查看次数: |
2475 次 |
最近记录: |