So we are used to writing redux selectors like this:
// state is the universal redux state
// shop is one of the combined reducers
// O(1)
const selectShop = state => state.shop;
// collections is an object - O(1)
export const selectCollections = createSelector(
[selectShop],
shop => shop.collections
);
//return all collections as an array - O(N)
export const selectCollectionsForPreview = createSelector(
[selectCollections],
collections => Object.keys(collections).map(key => collections[key])
);
With this set up, for a component if you wish to retrieve the collections as an array you could do this:
const mapStateToProps = createStructuredSelector({
collections: selectCollectionsForPreview
})
export default connect(mapStateToProps)(MyComponent);
When the component is rendered for the first time, the O(N) operation will take place but from the second time (of course assuming the state hasn't mutated) it will just returned the collections array from the cache which makes it an O(1) operation.
Now think of a selector that should return collections as an array but filtered based upon a url parameter
Then you would have to create a function that generates a createSelector
function that would look like this
which is an O(N) operation
export const selectFilteredCollections = urlParam =>
createSelector(
[selectCollections], // this returns the array as explained above and is memoized
collections => collections.filter(coll => coll.type === urlParam)
);
Now to use it you would do
const mapStateToProps = (state, ownProps) => ({
collections: selectFilteredCollections(ownProps.match.url)
});
export default connect(mapStateToProps)(MyComponent);
The problem here is you are creating a new function that returns a createSelector
function based on the url parameter each time the component renders.
So even if the url parameter remains the same for the second time of the call you are re creating a selector. So memoization didn't take place correctly.
In this situation, you will have to install loadash
library
If using yarn:
yarn add lodash.memoize
If using npm:
npm install lodash.memoize
And to use it, we import our newly installed memoize helper function like so
import memoize from 'lodash.memoize';
And just wrap our selectFilteredCollections function with memoize like so:
export const selectFilteredCollections = memoize((urlParam) =>
createSelector(
[selectCollections], // this returns the array as explained above and is memoized
collections => collections.filter(coll => coll.type === urlParam)
));
Memoize does the same idea of memoization as reselect does for our selectors, except this time we're memoizing the return of our function which returns our selector:
(urlParam) =>
createSelector(
[selectCollections],
collections => collections.filter(coll => coll.type === urlParam)
)
By wrapping this function is memoize, we're saying that whenever this function gets called and receives urlParam
, I want to memoize the return of this function (in this case we return a selector). If this function gets called again with the same urlParam
, don't rerun this function because we'll return the same value as last time, which we've memoized so just return the selector that's been stored.
Hope you had fun reading this !
Its my first post here :)
And oh ! did I forget to mention - you can learn more
at the official website Redux Reselect
Also if you want to dive deep into loadash.memoize , checkout this article that @CameronNokes wrote here on dev.to
Top comments (7)
always try for Time complexity of O(1) folks ! Space complexity isn't a big deal with modern browsers anymore
Ah, is the reason why open tab with facebook takes 1.5Gb of RAM that it's not a big deal? Gooootcha... :)
1.5GB ? 😶
Just to illustrate that space complexity still matters, and that time complexity in many cases can be easily sacrificed too. dev-to-uploads.s3.amazonaws.com/i/...
alright now I agree ☝️
;P did you actually upload the image to s3 bucket just to reply to the comment ?
No, there's a button below comment form, but it works weird... apparently it just uploads an image and gives you the link, so I just copied that link.