gpt4 book ai didi

当值相等时,Angular 和 NGRX 会阻止选择器在状态更改时发出相同的值

转载 作者:太空狗 更新时间:2023-10-29 17:35:21 25 4
gpt4 key购买 nike

我正在寻找一种解决方案,使我的选择器仅在与上次发出的值相比发生变化时才发出新值,而不仅仅是对商店的引用发生变化。

我的商店中有以下状态:

{
items: [],
loading: false,
selectedItemId: 1
}

我有以下选择器:

export const getSelectedItem = createSelector(getItemsState,
(state) => {
return state.selectedItemId === null ? null : state.items.find(item => item.id === state.selectedItemId)
}
);

当我对此选择器进行订阅时,每次都会触发,例如商店中的加载标志发生变化。我希望选择器在所选项目的值发生更改时仅发出一个值。 IE。从 1 到 2。但不是当状态对象的引用不同时。

我找到了解决问题的方法:

this.itemStore.select(getSelectedItem).distinctUntilChanged((x, y) => {
return x.id === y.id;
}).subscribe(item => {
// do something
});

但是,我想移动逻辑以使更新的 distinct 进入我的选择器,而不是将其放在调用端。

我理解为什么我有这种行为,因为框架只检查对象是否相等,并且当我们每次从 reducer 返回一个新的 ItemState 对象时存储引用发生变化。但是我找不到解决我的问题的方法,而且我无法想象我是唯一需要一个选择器的人,它只在有效值发生变化时更新。

reducer 的代码如下所示:

export function itemsReducer(state: ItemsState = initialItemsState, action: Action): ItemsState {
switch(action.type) {
case itemActions.ITEMS_LOAD:
return {
...state,
itemsLoading: true
};
case itemActions.ITEMS_LOAD_SUCESS:
return {
...state,
items: action.payload,
itemsLoading: false
};
// ... a lot of other similar actions
}
}

最佳答案

对于您当前的 reducer ,distinctUntilChanged 是处理此问题的正确操作符。解决这个问题的另一种方法是让你的 reducer 在更新项目时检测对象是否“功能未改变”,例如:

export function itemsReducer(state: ItemsState = initialItemsState, action: Action): ItemsState {
switch(action.type) {
case itemActions.ITEMS_LOAD:
return {
...state,
itemsLoading: true
};
case itemActions.ITEMS_LOAD_SUCESS:
return {
...state,
items: action.payload.map((newItem) => {
let oldItem = state.items.find((i) => i.id == newItem.id);
// If the item exists in the old state, and is deeply-equal
// to the new item, return the old item so things watching it
// know they won't need to update.
if (oldItem && itemEqual(newItem, oldItem)) return oldItem;

// Otherwise, return the newItem as either there was no old
// item, or the newItem is materially different to the old.
return newItem;
}),
itemsLoading: false
};
// ... a lot of other similar actions
}
}

您需要以某种方式实现 itemEqual 以检查深层逻辑相等性。在这里,您可以使用您对“相等”在功能上意味着什么的知识来决定该项目是否已更改,例如:

function itemEqual(item1, item2) {
// Need here to do a /deep/ equality check between
// the two items, e.g.:
return (item1.id == item2.id &&
item1.propertyA == item2.propertyA &&
item1.propertyB == item2.propertyB)
}

您可以使用类似 lodash 的 _.isEqual() 函数的东西,而不是实现您自己的 itemEqual 来对对象进行一般的深度相等性检查。

关于当值相等时,Angular 和 NGRX 会阻止选择器在状态更改时发出相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51961413/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com