reselect 的 createSelector:它是否对嵌套对象进行深度比较?

问题描述

如果 redux 中的“第二个”(嵌套对象)发生变化怎么办? 如果它做浅比较,它应该忽略变化而不是重新渲染。

我在文档中看到的所有示例,它们都基于简单的对象,浅比较是可以的

// assume state is:  {data: {first : {second { } } }}

const selectData = state => state.data;

const selectSecond = createSelector(
    selectData,data => data
);

解决方法

createSelector 使用 strict equality (===),这意味着当且仅当它们引用内存中的同一对象时,两个对象才被视为“相等”。这与 React 在比较 state 或比较 useEffect 依赖项时使用的检查类型相同。

浅相等意味着如果两个对象的所有属性都严格相等,则它们相等。

深度相等意味着两个对象在内容相同的情况下相等,而不管对象引用如何。由于数据的不可变性质,它的计算成本很高,并且在 React 或 Redux 中几乎不需要。


Redux 状态被认为是不可变的,因此您永远不应该遇到对象在内存中具有相同引用但具有不同内容的情况。每次属性更改时,您都必须创建一个新对象。如果 second 已更改,则 firstdata 将是新对象。

如果 redux 中的“第二个”(嵌套对象)发生变化怎么办?如果它做浅比较,它应该忽略变化而不是重新渲染。

只有在您的状态发生突变时才会遇到此问题。只要您的 reducer 是正确的,那么每当 state.data 更改时您都会重新渲染,因为任何更改都需要创建一个新对象。


以下是各种相等性检查的几个示例:

state => state

state 是严格相等、浅相等和深相等。

state => ({...state})

state 是浅等和深等。它不是严格相等,因为它是一个新对象。

state => ({...state,nested: {...state.nested}})

state 是深度相等的。它不是严格相等或浅相等,因为 nested 属性是一个新对象。

state => ({...state,number: 5})

state 有一个改变的属性,所以它没有通过所有的相等性检查。

state => {
  state.nested.number = 5;
  return state;
}

这是 React 或 Redux 中不允许的那种改变。 state 是严格相等的,因为我们返回了相同的 state 对象。它也是浅相等的,因为 state.nested 是同一个对象。它不是深度相等(除非之前的值为 5)。

state => {
  state.nested = 5;
  return state;
}

这也是不允许的。如果您对顶级属性进行变异,则 state 是严格相等但不是浅相等或深相等。