Angular NgRx:更新另一个状态片时不相关的选择触发

Angular NgRx:更新另一个状态片时不相关的选择触发,angular,ngrx,Angular,Ngrx,我在启用NxRx(v7)的应用程序中有一个“功能”状态,如下所示 状态 export interface DataPageState { dataReceivedTimestamp: number; formData: PageSaveDataState; // <--- setting this previewDataHeaderNames: string[] // } <--- calls select

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

状态

    export interface DataPageState {  
        dataReceivedTimestamp: number; 

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

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

        error: string;
        isLoading: boolean;  
    }
减速器

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

当我设置formData时,选择器触发

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

  this.subs.sink = this.store$.select(fromDataPreview.getPreviewData).subscribe(previewData => {      
    this.loadGridData(previewData.headers, previewData.previewData);
  });
当我路由到另一个页面时,就在路由之前,我调用一个操作,按照上面的
案例myActions.ActionTypes.SetPreviewFormData
设置表单数据

但是当我调用它时,我有上面的选择器fire,因此我设置(已经设置)网格数据的方法再次被调用。如果我将分派注释到
myActions.ActionTypes.SetPreviewFormData
中,这种行为将不再发生

我的问题是,为什么设置一个状态片会触发另一个选择片?据我所知,选择器的整个想法是仅当该选择器中涉及的属性时才获取通知,否则也可能只有一个选择器返回整个状态

你知道为什么会这样吗?或者我的假设是错的吗


提前谢谢

我必须再次检查,但我的假设是: 您的reducer通过扩展语法返回状态的一个完整的新对象(这是正确的):

现在,选择器缓存重置,所有选择器重新计算。 参见,例如,imo对其进行了相当好的解释

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

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

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的引用不会更改,并且选择器没有对您的状态的直接引用,因此组合选择器不会重新计算。

谢谢您的解释。以上工作。我想我明白了,选择器关注的是输入(而不是输出),因此我们首先需要另一个选择器来返回任何我们不希望在状态改变时总是改变的输入。我现在认为我(大多数)的选择器都做错了,因为我经常将“状态”作为直接输入。因此,通常每个属性都需要两个选择器——一个用于从状态获取属性,另一个则将此输出用作输入,然后在组件中使用。如果使用状态的单个属性作为返回值,则使用状态即输入基本上是好的。NGRX通过distinctUntilChanged操作符检查对象引用。如果previewData引用没有更改,它将不会发出另一个值。所以我的示例中的getPreviewData选择器是完全正确的。但是在组合选择器中,distinctUntilChanged不起作用,因为必须通过{previewData,previewDataHeaderNames}构建返回对象的新引用。正如doco所说,默认情况下,distinctUntilChanged使用===比较,对象引用必须匹配这很好,这意味着我们仍然可以免费获得简单值。
 return { previewData: state.previewData, headers: state.previewDataHeaderNames };
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 })
        
    );