Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by MartianTraveler070

How can I prevent unnecessary Redux re-renders when filtering active entities?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I want to retrieve only the active entities from my Redux store. I initially tried filtering directly in the selector, but realized that this causes a new array reference each time, leading to unwanted re-renders:

JAVASCRIPT
const activeEntities = useSelector( state => state.entities.filter(entity => entity.active) );

To work around this, I moved the filtering outside the selector:

JAVASCRIPT
const activeEntities = useSelector(state => state.entities) .filter(entity => entity.active);

This change should ensure that the component only re-renders when state.entities actually changes. However, is there a better way to optimize this with memoization? I know that a memoized selector can be written like so:

JAVASCRIPT
const selectActiveEntities = createSelector( (state) => state.entities.items, (items) => items.filter(entity => entity.active) );

In my view, this is functionally equivalent to my second example. My goal is to have the component re-render only when the actual active entities (i.e. the underlying values affected by the filter) change. How can I achieve this further?

2

Comments 0

Answers 3

Views 60

3 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

Using a selector that returns a new array every time will indeed force a re-render because JavaScript arrays are compared by reference. Using memoization (for example, with Reselect) helps ensure that the selector returns the same object reference when the computation’s inputs haven’t changed.

Below is an example using Reselect:

JAVASCRIPT
import { createSelector } from 'reselect'; const selectEntities = state => state.entities; export const selectActiveEntities = createSelector( [selectEntities], (entities) => entities.filter(entity => entity.active) );

Then in your component, you can use:

JAVASCRIPT
const activeEntities = useSelector(selectActiveEntities);

How it Works

  1. Memoization:
    Reselect will cache the result of the last call. So if the entities slice hasn’t changed (shallow equality), it will return the previous result of entities.filter(...). This means your component will receive the same array reference unless one of the entities (or the array itself) changes.

  2. Avoiding Unnecessary Re-renders:
    Since useSelector uses strict (referential) equality by default, returning the same array reference will prevent unnecessary re-renders even if the rest of your state changes.

Considerations

  • Reference Stability of state.entities:
    Ensure that your reducer maintains the same array reference for state.entities when no changes occur. If the reducer always returns a new array—even if the contents haven’t actually changed—then your memoized selector’s input will change, causing a re-computation and a new result array.

  • Deep Equality:
    If your entities themselves are objects that may be updated immutably (i.e., new object references), then the filtered result might change even if the “active” status remains the same. In these cases, you may need additional logic to avoid re-computation when the underlying “active” properties have not changed.

Using Reselect is generally the best practice to memoize derived data in Redux, ensuring that your components only re-render when there is an actual change in the computed value (in this case, the active entities).

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by LunarWatcher228 1 month ago

0
JAVASCRIPT
const selectActiveEntities = createSelector( (state) => state.entities.items, (items) => items.filter(entity => entity.active) );

This may be functionally equivalent to your first examples doing the work directly in or around the useSelector hook, but I suspect it's already providing the memoized result you want. const activeEntities = useSelector(selectActiveEntities); should be fine.

The only "improvement" I'd suggest is splitting up the selector such that you can memoize intermediate results. I believe it's preferable for selectors to work only 1-level deep when accessing into state properties, so each can be memoized for consumption by UI components or when used as input selector functions to other selectors.

Example:

JAVASCRIPT
const selectEntities = state => state.entities; const selectEntityItems = createSelector( [selectEntities], entities => entities.items, ); const selectActiveEntities = createSelector( [selectEntityItems], (entityItems) => entityItems.filter(entity => entity.active), );
JAVASCRIPT
import { useSelector } from 'react-redux'; import { selectActiveEntities } from '../path/to/selectors'; ... const activeEntities = useSelector(selectActiveEntities);

If you've further need to hint at selector value equality, especially when working with arrays, you should use the shallowEqual utility or custom equality function with useSelector.

See Equality Comparisons and Updates for complete details.

Example:

JAVASCRIPT
import { shallowEqual, useSelector } from 'react-redux'; import { selectActiveEntities } from '../path/to/selectors'; ... const activeEntities = useSelector(selectActiveEntities, shallowEqual);

No comments yet.

Answer by PlanetaryNavigator148 1 month ago

0

You are right about the point that even the third example is equivalent in terms of the rendering it will cause.

How createSelector() works is that the outputSelector will not run if the inputSelector output does not change, but if your state array reference changes, it will run. And in that case, since the output selector is using a .filter(), a new array will be created even if the active values are still the same.

Since you want to prevent rerender based on the active values you can use a customEquality function, which is passed in as the second argument of useSelector.

For example if you have the ids of each of your entities, ensure that you only rerender when they change:

JAVASCRIPT
const idCheck = (prevArr,newArr) => { //create array of ids const prevArrIds = prevArr.map(({id}) => id); const newArrIds = newArr.map(({id}) => id); //sort array prevArrIds.sort((a,b) => a-b); newArrIds.sort((a,b) => a-b); //join the array into a string and compare return prevArrIds.join('') !== newArrIds.join('') }; ... const activeEntities = useSelector(state => state.entities.filter(entity => entity.active), idCheck);

Of course the above idCheck will now always run when the store value changes.

The optional comparison function also enables using something like Lodash's _.isEqual() or Immutable.js's comparison capabilities. There are is shallowEqual from react-redux.

A minor optimization you can do is use the selector created from createSelector and then still use this custom equality method.

No comments yet.

Discussion

No comments yet.