首页 > 解决方案 > 将状态转换为其他对象的 NGRX 选择器会导致 ExpressionHasChanged 异常

问题描述

这个讨论之后,我们进入并更改了我们的选择器以返回“丰富”的对象。因此,我们的 NGRX 实体状态包含基本的 JavaScript 对象,但我们有返回丰富对象的状态选择器。

我们选择器中的相关代码片段:

const getAllAssets = createSelector(
  getAssetsState,
  getAllAssetModels,
  (state: AssetsState, assets) => {
    // if we just return assets, no error occurs(!)
    return assets.map(a => createAsset(a));    
  }
);

在组件 HTML 中:

<ab-assets
  data-test-id="data-filter"
  [assets]="assets$ | async"></ab-assets>

和组件 TS:

assets$: Observable<Asset[]>;

...

 ngOnInit() {
   this.assets$ = this.store.pipe(
     select(AssetsSelectors.assetsQuery.getAllAssets)
   );
 }

这一切都很好,但我们得到了著名的 ExpressionChangedAfterItHasBeenCheckedError。

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has 
changed after it was checked. Previous value: 'allData: [object Object]'. 
Current value: 'allData: [object Object],[object Object],[object Object],
[object Object],[object Object],[object Object]'.

.map() 函数似乎是问题所在,当我只返回资产数组时它工作正常。

@timdeschryver 在本主题中以非常相似的方法进行了回复,所以我不确定为什么它不起作用?

但是,当我不创建新数组而是修改现有数组时,它可以正常工作:

for (let i = 0; i < assets.length; i++) {
  assets[i] = createAsset(assets[i]);
}    
return assets;

所以关键问题是:为什么当我返回一个新数组时会出现 ExpressionHasChanged 错误?

标签: angularngrx

解决方案


问题不在于 .map(),而是我也在检索选择器中的状态这一事实。

所以,这有效:

const getAllAssets = createSelector(
  getAllAssetModels, assets => {
  return assets.map(a => createAsset(a));
});

这不起作用:

const getAllAssets = createSelector(
  getAssetsState,
  getAllAssetModels, (state, assets) => {
  return assets.map(a => createAsset(a));
});

还是觉得不对劲。。。


推荐阅读