如何用RxJS操作符根据抽屉与物品Observable的发射调用不同方法?
问题描述
我有一个带多抽屉的柜子,每个抽屉内有可操作物品:
- 用户切换抽屉时,Observable
D会触发; - 切换完成后,Observable
I会立即发射当前抽屉的物品数组,后续用户操作抽屉内物品时,I也会持续发射事件。
流行为示例:
Drawer(D): --D----------------------------D--... Items(I): -------I----I-----I-----I-----I----I--..
需求逻辑:
- 每次
D触发后,紧随的第一个I事件需调用setCurrentDrawerItems(); - 在未被新的
D中断时,后续所有I事件需调用userPickedItemFromDrawer()。
RxJS实现方案
这里提供两种简洁的实现方式,核心都是利用switchMap响应抽屉切换事件,同时区分当前抽屉的首次物品加载和后续用户操作:
方式一:拆分流处理
通过take(1)和skip(1)拆分I流,分别绑定对应处理函数:
import { switchMap, take, skip, merge, EMPTY } from 'rxjs'; // 假设已定义 drawer$ (Observable D) 和 items$ (Observable I) drawer$.pipe( switchMap(() => { // 提取当前抽屉的第一个物品事件 const initialLoad$ = items$.pipe( take(1), tap(items => setCurrentDrawerItems(items)) ); // 提取当前抽屉的后续用户操作事件 const userActions$ = items$.pipe( skip(1), tap(item => userPickedItemFromDrawer(item)) ); // 合并两个流,用EMPTY确保仅执行副作用不发射值 return merge(initialLoad$, userActions$).pipe(switchMap(() => EMPTY)); }) ).subscribe();
方式二:状态跟踪处理
用scan维护状态,判断是否为当前抽屉的首次I事件:
import { switchMap, scan, tap } from 'rxjs'; drawer$.pipe( switchMap(() => items$.pipe( scan((isFirstLoad, items) => { if (isFirstLoad) { setCurrentDrawerItems(items); return false; // 首次加载完成后,状态切换为非首次 } userPickedItemFromDrawer(items); return false; }, true) // 初始状态标记为首次加载 ) ) ).subscribe();
核心逻辑说明
- switchMap:每次
drawer$触发时,会自动取消之前对items$的订阅,确保我们只处理当前抽屉的I事件,完美实现"被D中断"的要求; - 方式一:通过流拆分明确区分首次加载和后续操作,逻辑直观,适合需要对两类事件做额外差异化处理的场景;
- 方式二:用
scan维护状态,代码更紧凑,适合逻辑简单的场景。
内容的提问来源于stack exchange,提问作者techi
相关产品推荐
相关产品推荐

