Redux中多次调用与单次调用useSelector的性能差异及三种写法优劣对比
Comparing
useSelector Patterns: Performance & Tradeoffs Great question—let’s break down these three Redux useSelector approaches, focusing on concrete performance differences, re-rendering behavior, and when to choose each one.
First, a quick recap of how useSelector works: it triggers a component re-render only if the value returned by the selector function has a different reference than the previous render (by default, it uses strict === comparison). That’s the key rule here.
1. Multiple Independent useSelector Calls (Code Snippet 1)
const prop1 = useSelector((state) => state.appModel.prop1); const prop2 = useSelector((state) => state.appModel.prop2); const prop3 = useSelector((state) => state.appModel.prop3); const prop4 = useSelector((state) => state.appModel.prop4);
- Performance & Re-rendering: This is the most precise approach. Each selector only watches a single property—so the component will re-render only when the specific property it’s using changes. For example, if
prop2updates, only that selector’s return value changes, so the component re-renders once, and only for that update. The overhead of multipleuseSelectorcalls is negligible in practice; Redux optimizes these under the hood. - Pros: Granular control over re-renders, clear and explicit code (each property’s source is obvious).
- Cons: Slightly more verbose code.
2. Single useSelector Returning an Object (Code Snippet 2)
const { prop1, prop2, prop3, prop4 } = useSelector((state) => ({ prop1: state.appModel.prop1, prop2: state.appModel.prop2, prop3: state.appModel.prop3, prop4: state.appModel.prop4, }));
- Your initial intuition: You’re right that this uses one
useSelectorcall instead of four—but without extra configuration, it’s worse for re-renders. The selector returns a new object literal{}every time state changes (even if none of the properties update). Since the object reference is always new,useSelectorwill trigger a re-render on any state change, even unrelated ones. - Fix for performance: Add Redux’s
shallowEqualas the second argument touseSelector:import { shallowEqual, useSelector } from 'react-redux'; const { prop1, prop2, prop3, prop4 } = useSelector( (state) => ({ prop1: state.appModel.prop1, prop2: state.appModel.prop2, prop3: state.appModel.prop3, prop4: state.appModel.prop4, }), shallowEqual );shallowEqualcompares the individual properties of the returned object instead of checking reference equality. Now the component only re-renders if one ofprop1-prop4actually changes—matching the performance of Snippet 1. - Pros: More compact code, groups related properties together.
- Cons: Requires remembering to use
shallowEqualto avoid unnecessary re-renders; slightly less explicit than Snippet 1.
3. Directly Destructuring appModel (Code Snippet 3)
const { prop1, prop2, prop3, prop4 } = useSelector((state) => state.appModel);
- Performance & Re-rendering: This is the riskiest for unnecessary re-renders. If
appModelis updated immutably (as is standard in Redux), any change to any property inappModel(even one you don’t use, likeprop5) will create a newappModelreference. That means your component will re-render every timeappModelchanges at all—even if none ofprop1-prop4are updated. - Pros: Extremely concise code.
- Cons: Overly broad re-render triggers; only safe if you know
appModelwill never have extra properties, or if you want the component to re-render on anyappModelchange.
Choosing the Right Approach: Objective vs. Preference
This isn’t just about personal preference—there are clear objective tradeoffs:
- Prioritize minimal re-renders: Use Snippet 1, or Snippet 2 with
shallowEqual. - Prioritize code brevity (and trust your state shape): Use Snippet 3 only if you’re certain
appModelwon’t have extra properties that could trigger unwanted re-renders. - Readability matters: Snippet 1 is the most explicit for other developers reading your code, while Snippets 2 and 3 are more compact but require understanding of
shallowEqualor state shape.
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

