通过同时使用记忆选择器和相等比较函数,“useSelector”是否有任何性能优势?

Is there any performance benefit for `useSelector` by using together both a memoizing selector AND an equality comparison function?

我的 List 组件中有以下逻辑:

const List = React.memo(() => {
    const apples = useSelector(
        (state) => Object.values(state.apples),
        (currentState, prevState) => currentState.length === prevState.length,
    );

  return 'whatever';
);

这在渲染时间方面给了我很好的结果 -> 它只渲染一次并仅在“苹果”的长度发生变化时重新渲染,而不是在苹果的属性发生变化时重新渲染。

但是,我想知道添加 memoized selector 是否会带来任何性能优势?

为了说明我的例子:

const applesSelector = createSelector(
    (state) => Object.values(state.apples)
)

const List = React.memo(() => {
    const apples = useSelector(
        applesSelector,
        (currentState, prevState) => currentState.length === prevState.length,
    );

  return 'whatever';
);

所以我很难找到 useSelector 通过同时使用记忆选择器和相等比较函数是否有性能优势?

首先,applesSelector 的示例实现似乎存在错误。正确的实现是:

const applesSelector = createSelector(
  state => state.apples,
  apples => Object.values(apples)
)

这样,输出选择器实际上只在 state.apples 发生变化时运行。

对于您的实际问题:如果您使用的是记忆选择器,通常不需要向 useSelector 添加相等比较参数,因为进行比较的工作已经发生选择器函数内部。

记忆化在重新选择时非常有用,但您获得的主要好处是可组合的选择器。您可以在一个选择器中回答一个问题,而不是在 1 个选择器中回答 2 个问题(苹果在哪里以及我 return 它们的形状),您可以在一个选择器中回答一个问题“selectAppes 中的苹果在哪里”和“我 return them" 作为 selectApplesAsArray,它使用 selectApples 获取苹果。这可以防止重复实施。

苹果的例子有些简单,但 React 应用程序的选择器中可能有复杂的业务规则,您不想重复这些规则。像 selectPolicyPrice 这样的东西可能需要重新使用其他选择器来防止重复实现,当政策定价规则发生变化时,这会导致难以修复的错误。

有时您可能想要记住数组结果,例如当您执行 Object.keys、Object.values 或 Array.prototype.filter.

const { createSelector, defaultMemoize } = Reselect;

const createMemArray = () => {
  const memArr = defaultMemoize((...arr) => arr);
  return (arr) => memArr(...arr);
};
const selectApples = (state) => state.apples;
const selectApplesAsArray = ((
  mem //mem will memoize array
) =>
  createSelector([selectApples], (apples) =>
    mem(Object.values(apples))//memoize each item in apples
  ))(createMemArray()); //IIFE createing memoized array

const state = { apples: { a: 1, b: 2 } };
const a = selectApplesAsArray(state),
  b = selectApplesAsArray({
    ...state,
    //copied, will not recalculate because of memoize array
    apples:{...state.apples},
    irrelevantChange: 22,
  });
console.log('a is b:', a === b);
console.log('a and b are:', a);
const c = selectApplesAsArray({
  ...state,
  apples: { ...state.apples, b: 'changed' },
});
console.log('c is b:', c === b);
console.log('c is:', c);
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>


<div id="root"></div>

我写了一些 short examples 选择器如何与 redux 一起使用,可能会有帮助。