You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ngrx中日期范围订阅在其他无关状态变更时意外触发是什么原因?

问题原因

  1. NgRx 中任意 action 派发后,对应的状态切片只要发生修改,就会返回一个全新的状态对象引用。你派发ResetPageIndex这类 action 时,虽然没有修改start和end属性,但整个 transaction 状态切片的引用已经发生了变更,会触发所有依赖该状态切片的选择器重新执行。
  2. 你当前的selectStartAndEndDate选择器的投影函数每次执行都会返回一个新的对象字面量{ start: state.start, end: state.end },哪怕start和end的值完全没有变化,这个返回对象的引用也是全新的。而 NgRx 选择器默认使用引用相等判断返回值是否发生变化,所以每次选择器重新执行都会认为产生了新值,进而触发订阅回调。

解决方案

有三种常用的修复方案,你可以根据自己的项目情况选择:

  • 方案1:给选择器添加自定义相等比较器
    你可以在创建选择器时指定结果相等检查逻辑,直接对返回对象的内容做对比,而不是只对比引用。如果不想引入第三方工具库,也可以自行实现日期比较逻辑替换示例中的isEqual:
    import { createSelector, defaultMemoize } from '@ngrx/store';
    import { isEqual } from 'lodash-es'; 
    
    export const selectStartAndEndDate = createSelector(
      selectTransactionState,
      (state) => ({ start: state.start, end: state.end }),
      { memoize: defaultMemoize, resultEqualityCheck: isEqual }
    );
    
  • 方案2:拆分选择器后组合使用
    把start和end拆成两个独立的选择器,再用combineLatest组合,只有当两个属性本身的值发生变化时才会触发回调:
    // 选择器定义
    export const selectStartDate = createSelector(selectTransactionState, state => state.start);
    export const selectEndDate = createSelector(selectTransactionState, state => state.end);
    
    // 组件内使用
    combineLatest([
      this.store.select(selectStartDate),
      this.store.select(selectEndDate)
    ]).subscribe(([start, end]) => {
      this.range.setValue({ start, end });
    });
    
  • 方案3:订阅时添加去重操作符
    如果你不想修改选择器定义,可以直接在订阅的流中添加distinctUntilChanged操作符手动去重:
    import { distinctUntilChanged } from 'rxjs';
    import { isEqual } from 'lodash-es';
    
    this.subs.sink = this.store
      .select(fromTransactionReducer.selectStartAndEndDate)
      .pipe(distinctUntilChanged(isEqual))
      .subscribe((date) => {
        console.log("range", date);
        this.range.setValue({
          start: date.start,
          end: date.end,
        });
      });
    

内容的提问来源于stack exchange,提问作者walexy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 00:39:03