通过同时使用记忆选择器和相等比较函数,“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 一起使用,可能会有帮助。
我的 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 一起使用,可能会有帮助。