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