Redux Toolkit createSelector vs React-Redux useSelector: Handling Stale Cache Results
0 reputation · 22 Feb 2022, 12:50 UTC
0 reputation · 22 Feb 2022, 12:50 UTC
Understand how stale cache outputs from createSelector can affect UI updates driven by useSelector, and identify the decision point around memoization equality strategy.
Selectors memoize based on reference equality of input values. When an input selector returns a new object or array that is shallowly equal to the previous one, createSelector treats it as a change and recomputes, potentially causing unnecessary work. The React component will re‑render only if the selector result reference changes, but stale recomputations can delay the display of updated data until the next action triggers a cache reset.
Redux Toolkit’s repository discussion questions whether createSelector should adopt deep equality checks for its inputs to avoid stale recomputations, weighing correctness against performance overhead.
createSelector use deep equality for input selectors to prevent stale recomputations?useSelector receives fresh data when input selectors return structurally identical but newly allocated objects?1. Should createSelector use deep equality for inputs? No. The library intentionally uses strict reference equality (===) because deep equality adds O(n) overhead on every selector call, which becomes costly in large state trees and high-frequency dispatches.
2. How can developers guarantee useSelector receives fresh data when input selectors return new but structurally identical objects? Ensure input selectors return stable references. Do this by returning existing state slices directly, memoizing derived data with useMemo (or createSelector itself), and using immutable update patterns that reuse objects when contents haven’t changed.
3. What are the performance trade‑offs of switching to deep equality in large state trees? Deep equality forces a full tree walk on every selector evaluation. For a 10,000‑item array this can add milliseconds per call, and with frequent dispatches the cumulative latency often outweighs the occasional stale recomputation it prevents.
Confirmed: createSelector memoizes based on reference equality of its input selector results. If an input selector returns a newly allocated object that is shallowly equal to the previous one, createSelector treats it as a change and re‑runs the output selector.
Confirmed: useSelector only triggers a component re‑render when the selector result reference changes. If the output selector returns the same reference after recomputation, the component does not re‑render, so the UI may show stale data until another action produces a new reference.
Likely explanation: This mismatch means a component can miss an update even though the derived data was recomputed, because the memoization cache was invalidated by a new input reference that happened to be structurally identical.
state => state.todos).createSelector or useMemo so the same reference is reused when the underlying data hasn’t changed.createSlice with Immer) that preserve references for unchanged nested data.Deep equality scales linearly with the size of the compared values. In a typical app with many selectors and frequent updates, the added comparison cost can degrade responsiveness more than the occasional unnecessary recomputation. Benchmark your specific state shape before considering a custom equality function.
What is the typical size and nesting depth of the state slices fed into the problematic selectors? If they are small (a few dozen keys), a custom shallow-deep equality might be acceptable; if they are large, the cost will likely outweigh the benefit.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.