不相关 select 在更新另一个状态片时触发

Unrelated select firing when updates another slice of state

我在启用 NxRx (v7) 的应用程序中有一个“功能”状态,如下所示:

    export interface DataPageState {  
        dataReceivedTimestamp: number; 

        formData: PageSaveDataState;      // <--- setting this

        previewDataHeaderNames: string[]  // } <--- calls selector for these
        previewData: string[][];          // }

        error: string;
        isLoading: boolean;  
    }

选择器

我有一个 selector 来获取 previewDataHeaderNames previewData - 作为对象返回,因为我使用它们来填充数据网格:

export const getDataPreviewFeatureState = createFeatureSelector<DataPreviewPageState>(NgRxStateNames.dataPreviewPage);

    /** Get preview data */
    export const getPreviewData = createSelector(
        getDataPreviewFeatureState,
        (state: DataPreviewPageState) => {
            return { previewData: state.previewData, headers: state.previewDataHeaderNames };
        }
    );

减速机

在我的减速器中,我有以下内容来更新 formData 状态片。我在同一页上有一个表单,我用它来保存它的状态(以及数据网格布局等):

case myActions.ActionTypes.SetPreviewFormData: {
    this.logger.info('SetPreviewFormData');
    const newState = { ...action.payload, timeStamp: this.timeService.getUtcNowTimestamp() }
    return { ...state, formData: newState };
  }

选择器在我设置 formData 时触发

最后,在我的组件代码中,我有一个 selector 用于 getPreviewData

  this.subs.sink = this.store$.select(fromDataPreview.getPreviewData).subscribe(previewData => {      
    this.loadGridData(previewData.headers, previewData.previewData);
  });

当我路由到另一个页面时,就在我路由之前,我调用了一个操作来按照上面的 case myActions.ActionTypes.SetPreviewFormData 设置表单数据。

但是当我调用这个时,我有上面的 selector fire,所以我设置(已经设置)网格数据的方法再次被调用。如果我注释掉我对 myActions.ActionTypes.SetPreviewFormData 的调度,这种行为将不再发生。

为什么设置状态的一个切片会触发 select 不同的切片?据我了解,selectors 的整个想法是仅在 属性 涉及 selector 时才收到通知,否则也可能只有一个 select或者 returns 整个州。

为什么会这样,还是我的假设有误?

我必须仔细检查,但我的假设是: 您的减速器 returns 通过扩展语法(这是正确的)状态的一个完整的新对象:

 return { previewData: state.previewData, headers: state.previewDataHeaderNames };

现在,选择器缓存会重置,所有选择器都会重新计算。 参见例如https://medium.com/swlh/memoization-with-selectors-in-ngrx-c60e67a08161,我解释得很好。

我认为您可以通过以下模式实现您想要的效果:

首先,为您需要的两个单一状态属性定义两个选择器:

export const getPreviewData = createSelector(
    getDataPreviewFeatureState,
    (state: DataPreviewPageState) => state.previewData 
    }
);

export const getPreviewDataHeaderNames = createSelector(
    getDataPreviewFeatureState,
    (state: DataPreviewPageState) => state.previewDataHeaderNames 
    }
);

然后组合这两个选择器来为您的组件定义选择器:

    export const getPreviewDataWithNames = createSelector(
        getPreviewData,
        getPreviewDataHeaderNames,
        (previewData, previewDataHeaderNames) => ({ previewData, previewDataHeaderNames })
        
    );

现在应该会发生以下情况:由于 previewData 和 previewDataHeaderNames 的引用没有改变并且选择器没有直接引用您的状态,因此您的组合选择器不会重新计算。