如何阻止特定store selector在指定store action派发时emit值?
问题根因
你之前的race方案失效核心有两个原因:
- NgRx 的
dispatch和selector值通知默认是同步执行的,靠delay硬控时序本身就不可靠,遇到主线程阻塞场景必然会逻辑错乱 race只会取第一个触发的流,后续流的事件会被直接丢弃,不符合你只跳过特定事件、后续正常接收的需求
可行方案1:标志位过滤(适合单次跳过场景,实现最简单)
首先维护一个控制跳过的标志流:
// 组件内定义,默认不需要跳过 private skipNextEmit$ = new BehaviorSubject<boolean>(false);
派发特殊action前先标记需要跳过下一次selector emit:
this.skipNextEmit$.next(true); this.store.dispatch(someAction({ payload: { value } }));
修改selector订阅的pipe逻辑,过滤掉标记跳过的事件:
this.store.select(state => state.someProperty).pipe( takeUntil(this.destroy$), // 组合最新的跳过标记 withLatestFrom(this.skipNextEmit$), filter(([val, shouldSkip]) => { if (shouldSkip) { // 跳过本次后重置标记,不影响后续正常事件 this.skipNextEmit$.next(false); return false; } return true; }), // 提取出真实的state值 map(([val]) => val) ).subscribe(val => { dosomething(); })
可行方案2:计数跳过(适合短时间内多次触发跳过的场景,更稳妥)
如果存在连续多次派发特殊action、需要跳过对应次数selector emit的场景,可以用scan维护跳过计数,避免错漏:
// 组件内定义跳过信号流 private skipSignal$ = new Subject<void>(); // 派发特殊action前发送跳过信号 this.skipSignal$.next(); this.store.dispatch(someAction({ payload: { value } }));
selector订阅逻辑修改为:
merge( // 跳过信号标记需要多跳1次 this.skipSignal$.pipe(map(() => ({ type: 'skip' }))), // 正常的selector值流 this.store.select(state => state.someProperty).pipe(map(val => ({ type: 'value', payload: val }))) ).pipe( takeUntil(this.destroy$), // 维护剩余需要跳过的次数 scan((acc, curr) => { if (curr.type === 'skip') { return { skipCount: acc.skipCount + 1, value: null }; } if (curr.type === 'value') { if (acc.skipCount > 0) { return { skipCount: acc.skipCount - 1, value: null }; } return { skipCount: 0, value: curr.payload }; } return acc; }, { skipCount: 0, value: null }), // 过滤掉跳过的事件,只保留需要处理的值 filter(res => res.value !== null), map(res => res.value) ).subscribe(val => { dosomething(); })
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

