Angular & NGRX prevent selector from emitting identical value on state change when values are equal

邮差的信 提交于 2019-12-04 08:08:19

With your current reducer, distinctUntilChanged is the correct operator to handle this. Another way to address this would be by making your reducer detect whether the object is "functionally unchanged" when updating the items, for example, something like:

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
    }
}

You would need to implement itemEqual somehow to check for deep logical equality. This is where you use your knowledge of what, functionally, "equal" means to decide whether the item has changed, for example:

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)
}

You could use something like lodash's _.isEqual() function instead of implementing your own itemEqual for a general deep equality check on the objects.

Add a check in your reducer, which checks the current state. and the payload. if the payload value is identical to your current state, do not override the state. but return the current state as it is. and your reducer will fire only if the values and reference is indeed changed.

like:

case 'XXXSTATE':  
if(state.xxx.value === payload.value)
       return state; 
else 
       return {...state,itemsLoading: true};

Also redux not only checks for references, but that is an another topic :)

The problem with your code is you are returning the same value back. To trigger change you have to return a new object not a reference to existing value.

return state.selectedItemId === null ? null : Object.assign({}, state.items.find(item => item.id === state.selectedItemId))
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!