NGXS Select返回的Observable应用RxJS timeout操作符不生效问题
问题原因
- NGXS 的
@Select装饰器返回的 Observable 默认自带去重逻辑:只有 selector 计算出的新值和上一次发射值通过===全等判定不相等时,才会向下游推送新值。 - 常见触发去重的两种场景:
- 你每10秒更新状态时传入的
myValue和上一次的数值完全相等 - 状态更新没有遵循不可变原则:直接修改原状态对象的属性,没有返回全新的状态对象,导致 selector 拿到的引用和上一次一致,被判定为无变化
- 你每10秒更新状态时传入的
- 上述两种情况都会导致
myValue$在首次推送初始值后,后续不会再推送任何新事件,timeout操作符的计时器无法被重置,自然会在订阅满20秒时抛出超时错误。 - 而
interval(10000)每次都会推送全新的递增值,每10秒都会触发一次事件重置timeout计时器,所以不会触发超时。
解决方案
方案1:修正状态更新逻辑
确保每次状态更新都遵循不可变原则,且如果业务上需要触发 selector 发射,要传入和上一次不同的值,示例状态更新代码:
@Action(UpdateMyValue) updateMyValue(ctx: StateContext<MyStateModel>, action: UpdateMyValue) { // 正确:返回全新的状态对象,不要直接修改原state的属性 return ctx.setState({ ...ctx.getState(), myValue: action.newValue // 确保newValue和上一次的值不相等 }) }
方案2:关闭 selector 默认去重
如果你需要不管值是否变化,只要执行了状态更新就推送事件,可以关闭 selector 的默认去重逻辑,不使用 @Select 装饰器,改为手动注入 StateService 调用 select 方法并传入配置:
import { StateService } from '@ngxs/store'; constructor(private stateService: StateService) { // suppressDistinct设为true即可关闭去重 this.myValue$ = this.stateService.select(MyState.myValue, { suppressDistinct: true }); }
方案3:调整超时监听逻辑
如果你的业务需求就是监听「状态值是否发生变更」,不需要监听更新动作,可以将超时时间调整为大于两次实际值变更的最大间隔即可。
内容的提问来源于stack exchange,提问作者Bonney Ramirez
相关产品推荐
相关产品推荐

