Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reselect - does it ever make sense to create a memorized selector which is just used to get part of the state?

Tags:

redux

reselect

I have a normal selector which is just used to get part of the state:

export const getAllPosts = state => {
  return state.posts;
};

If I use the reselect to wrap the selector:

import { createSelector } from 'reselect';

export const allPosts = createSelector(
  getAllPosts,
  (posts) => posts
);

Does it make any sense such as improving performance ? In my opinion, the wrapper is unnecessary.

like image 567
Jason Xu Avatar asked Nov 07 '17 10:11

Jason Xu


People also ask

What is reselect and how it works?

Reselect provides a function called createSelector to generate memoized selectors. createSelector accepts one or more "input selector" functions, plus an "output selector" function, and returns a new selector function for you to use.

Why should I use reselect?

Reselect is useful because you can compose selectors and the memoization can prevent expensive selector code from running. The memoization can also prevent needless re renders. What you should consider is maintainable code and with reselect you can write selector logic once and re use it by composing selectors.

What is the purpose of memoized selectors provided by the reselect library?

Reselect is a library for building memoized selectors. We define selectors as the functions that retrieve snippets of the Redux state for our React components. Using memoization, we can prevent unnecessary rerenders and recalculations of derived data which in turn will speed up our application.

What is createSelector reselect?

Reselect exports a createSelector API, which generates memoized selector functions. createSelector accepts one or more "input" selectors, which extract values from arguments, and an "output" selector that receives the extracted values and should return a derived value.


2 Answers

No, it does not make sense to create a memoized selector just to get part of the state tree.

The reason is that connect will do it’s own shallow equality check for each prop passed in from mapStateToProps. If the prop returned by the selector passes that shallow equality check, along with the other props, then render will not be called unnecessarily. If the selector simply returned a part of the state tree and that part of the state tree had not been modified then a shallow equality check will be sufficient.

However, If the selector is computed from the results of other selectors then using createSelector is a good choice. Firstly, it provides a nice syntax for composing selectors. Secondly, if the computation of combining the selectors is potentially expensive you will get a performance benifit. Thirdly, if the selector was to return a new, but equivelent, object or array then the shallow equality check provided by connect would not be sufficient. In that case the memoization that createSelector provides would ensure that the same object or array instance was returned if the inputs had not changed and then the shallow equality check would be sufficient to avoid costly re-renders.

So for just exposing parts of the state tree createSelector doesn’t add anything.

For nearly all selectors that are computed from multiple parts of the state tree createSelector begins to add value. The amount of value that it adds varies based on the selector from just being easier to read up to ensuring you don’t re render the component tree unnecessarily.

like image 155
Chad Edrupt Avatar answered Oct 01 '22 14:10

Chad Edrupt


In your case it does not make sense cause you just return the same reference from the store which is always shallow equal to itself (or it's previous state) unless you modify it.

If you imagine a different scenario for example a scenario where you store your entities in an object instead of an array in the store but you want to return an array to your Component then you need to derive data:

export const selectAllPosts = createSelector(
  getAllPostsFromStore, // returns { 1: {...}, 2: {...} }
  (allPosts) => Object.keys(allPosts).map(key => allPosts[key])
);

Now your selector turned into a performance boost cause it only computes the derived data when something in the store changes.

So my rule of thumb is: If you don't derive data, you don't need to memoize it.

like image 25
larrydahooster Avatar answered Oct 01 '22 15:10

larrydahooster