Installations
npm install @veksa/re-reselect
Developer Guide
Typescript
Yes
Module System
CommonJS, ESM
Node Version
21.5.0
NPM Version
9.6.6
Score
76.6
Supply Chain
97.4
Quality
78.5
Maintenance
100
Vulnerability
100
License
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (84.51%)
JavaScript (15.49%)
Love this project? Help keep it running — sponsor us today! 🚀
Developer
toomuchdesign
Download Statistics
Total Downloads
863
Last Day
12
Last Week
59
Last Month
324
Last Year
863
GitHub Statistics
MIT License
1,085 Stars
477 Commits
46 Forks
8 Watchers
3 Branches
17 Contributors
Updated on Feb 14, 2025
Bundle Size
4.42 kB
Minified
1.37 kB
Minified + Gzipped
Package Meta Information
Latest Version
5.1.1-p3
Package Id
@veksa/re-reselect@5.1.1-p3
Unpacked Size
550.76 kB
Size
46.09 kB
File Count
40
NPM Version
9.6.6
Node Version
21.5.0
Published on
Sep 27, 2024
Total Downloads
Cumulative downloads
Total Downloads
863
Last Day
33.3%
12
Compared to previous day
Last Week
7.3%
59
Compared to previous week
Last Month
29.6%
324
Compared to previous month
Last Year
0%
863
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Re-reselect
From v5, reselect
provides the ability to natively implement custom memoization/caching solutions via createSelector
options. Most of the features re-reselect
used to enable should be now natively available in reselect
. re-reselect
will try to support reselect
v5+ for backward compatibility reasons.
re-reselect
is a lightweight wrapper around Reselect meant to enhance selectors with deeper memoization and cache management.
Switching between different arguments using standard reselect
selectors causes cache invalidation since default reselect
cache has a limit of one.
re-reselect
forwards different calls to different reselect
selectors stored in cache, so that computed/memoized values are retained.
re-reselect
selectors work as normal reselect
selectors but they are able to determine when creating a new selector or querying a cached one on the fly, depending on the supplied arguments.
Useful to:
- Retain selector's cache when sequentially called with one/few different arguments (example)
- Join similar selectors into one
- Share selectors with props across multiple component instances (see reselect example and re-reselect solution)
- Instantiate selectors on runtime
- Enhance
reselect
with custom caching strategies
1import {createCachedSelector} from 're-reselect'; 2 3// Normal reselect routine: declare "inputSelectors" and "resultFunc" 4const getUsers = state => state.users; 5const getLibraryId = (state, libraryName) => state.libraries[libraryName].id; 6 7const getUsersByLibrary = createCachedSelector( 8 // inputSelectors 9 getUsers, 10 getLibraryId, 11 12 // resultFunc 13 (users, libraryId) => expensiveComputation(users, libraryId), 14)( 15 // re-reselect keySelector (receives selectors' arguments) 16 // Use "libraryName" as cacheKey 17 (_state_, libraryName) => libraryName 18); 19 20// Cached selectors behave like normal selectors: 21// 2 reselect selectors are created, called and cached 22const reactUsers = getUsersByLibrary(state, 'react'); 23const vueUsers = getUsersByLibrary(state, 'vue'); 24 25// This 3rd call hits the cache 26const reactUsersAgain = getUsersByLibrary(state, 'react'); 27// reactUsers === reactUsersAgain 28// "expensiveComputation" called twice in total
Table of contents
Installation
1npm install reselect 2npm install re-reselect
Why? + example
Let's say getData
is a reselect
selector.
1getData(state, itemId, 'dataA'); 2getData(state, itemId, 'dataB'); 3getData(state, itemId, 'dataA');
The 3rd argument invalidates reselect
cache on each call, forcing getData
to re-evaluate and return a new value.
re-reselect solution
re-reselect
selectors keep a cache of reselect
selectors stored by cacheKey
.
cacheKey
is the return value of the keySelector
function. It's by default a string
or number
but it can be anything depending on the chosen cache strategy (see cache objects docs).
keySelector
is a custom function which:
- takes the same arguments as the selector itself (in the example:
state
,itemId
,dataType
) - returns a
cacheKey
A unique persisting reselect
selector instance stored in cache is used to compute data for a given cacheKey
(1:1).
Back to the example, we might setup re-reselect
to retrieve data by querying one of the cached selectors using the 3rd argument as cacheKey
, allowing cache invalidation only when state
or itemId
change (but not dataType
):
1const getData = createCachedSelector( 2 state => state, 3 (state, itemId) => itemId, 4 (state, itemId, dataType) => dataType, 5 (state, itemId, dataType) => expensiveComputation(state, itemId, dataType) 6)( 7 (state, itemId, dataType) => dataType // Use dataType as cacheKey 8);
Replacing a selector with a cached selector is invisible to the consuming application since the API is the same.
When a cached selector is called, the following happens behind the scenes:
- Evaluate the
cacheKey
for the current call by executingkeySelector
- Retrieve from cache the
reselect
selector stored under the givencacheKey
- Return found selector or create a new one if no selector was found
- Call returned selector with provided arguments
Other viable solutions
1- Declare a different selector for each different call
Easy, but doesn't scale. See "join similar selectors" example.
2- Declare a makeGetPieceOfData
selector factory as explained in Reselect docs
The solution suggested in Reselect docs is fine, but it has a few downsides:
- Bloats your code by exposing both
get
selectors andmakeGet
selector factories - Needs to import/call the selector factory instead of directly using the selector
- Two different instances, given the same arguments, will individually store and recompute the same result (read this)
3- Wrap your makeGetPieceOfData
selector factory into a memoizer function and call the returning memoized selector
This is what re-reselect
actually does. 😀
Examples
- Join similar selectors
- Avoid selector factories
- Cache API calls
- Programmatic keySelector composition
- Usage with Selectorator
FAQ
How do I wrap my existing selector with re-reselect?
Given your reselect
selectors:
1import {createSelector} from '@veksa/reselect'; 2 3export const getMyData = createSelector( 4 selectorA, 5 selectorB, 6 selectorC, 7 (A, B, C) => doSomethingWith(A, B, C) 8);
...add keySelector
in the second function call:
1import {createCachedSelector} from 're-reselect'; 2 3export const getMyData = createCachedSelector( 4 selectorA, 5 selectorB, 6 selectorC, 7 (A, B, C) => doSomethingWith(A, B, C) 8)( 9 (state, arg1, arg2) => arg2 // Use arg2 as cacheKey 10);
Voilà, getMyData
is ready for use!
1const myData = getMyData(state, 'foo', 'bar');
How do I use multiple inputs to set the cacheKey?
A few good examples and a bonus:
1// Basic usage: use a single argument as cacheKey 2createCachedSelector( 3 // ... 4)( 5 (state, arg1, arg2, arg3) => arg3 6) 7 8// Use multiple arguments and chain them into a string 9createCachedSelector( 10 // ... 11)( 12 (state, arg1, arg2, arg3) => `${arg1}:${arg3}` 13) 14 15// Extract properties from an object 16createCachedSelector( 17 // ... 18)( 19 (state, props) => `${props.a}:${props.b}` 20)
How do I limit the cache size?
Use a cacheObject
which provides that feature by supplying a cacheObject
option.
You can also write your own cache strategy!
How to share a selector across multiple components while passing in props and retaining memoization?
This example shows how re-reselect
would solve the scenario described in reselect docs.
How do I test a re-reselect selector?
Like a normal reselect selector!
re-reselect
selectors expose the same reselect
testing methods:
dependencies
resultFunc
recomputations
resetRecomputations
Read more about testing selectors on reselect
docs.
Testing reselect
selectors stored in the cache
Each re-reselect selector exposes a getMatchingSelector
method which returns the underlying matching selector instance for the given arguments, instead of the result.
getMatchingSelector
expects the same arguments as a normal selector call BUT returns the instance of the cached selector itself.
Once you get a selector instance you can call its public methods.
1import {createCachedSelector} from 're-reselect'; 2 3export const getMyData = createCachedSelector(selectorA, selectorB, (A, B) => 4 doSomethingWith(A, B) 5)( 6 (state, arg1) => arg1 // cacheKey 7); 8 9// Call your selector 10const myFooData = getMyData(state, 'foo'); 11const myBarData = getMyData(state, 'bar'); 12 13// Call getMatchingSelector method to retrieve underlying reselect selectors 14// which generated "myFooData" and "myBarData" results 15const myFooDataSelector = getMyData.getMatchingSelector(state, 'foo'); 16const myBarDataSelector = getMyData.getMatchingSelector(state, 'bar'); 17 18// Call reselect's selectors methods 19myFooDataSelector.recomputations(); 20myFooDataSelector.resetRecomputations();
API
createCachedSelector
1import {createCachedSelector} from 're-reselect'; 2 3createCachedSelector( 4 // ...reselect's `createSelector` arguments 5)( 6 keySelector | { options } 7)
Takes the same arguments as reselect's createSelector
and returns a new function which accepts a keySelector
or an options
object.
Returns a selector instance.
createStructuredCachedSelector
1import {createStructuredCachedSelector} from 're-reselect'; 2 3createStructuredCachedSelector( 4 // ...reselect's `createStructuredSelector` arguments 5)( 6 keySelector | { options } 7)
Takes the same arguments as reselect's createStructuredSelector
and returns a new function which accepts a keySelector
or an options
object.
Returns a selector instance.
keySelector
A custom function receiving the same arguments as your selectors (and inputSelectors
) and returning a cacheKey
.
cacheKey
is by default a string
or number
but can be anything depending on the chosen cache strategy (see cacheObject
option).
The keySelector
idea comes from Lodash's .memoize resolver.
options
keySelector
Type: function
Default: undefined
The keySelector
used by the cached selector.
cacheObject
Type: object
Default: FlatObjectCache
An optional custom cache strategy object to handle the caching behaviour. Read more about re-reselect's custom cache here.
keySelectorCreator
Type: function
Default: undefined
An optional function with the following signature returning the keySelector
used by the cached selector.
1type keySelectorCreator = (selectorInputs: { 2 inputSelectors: InputSelector[]; 3 resultFunc: ResultFunc; 4 keySelector: KeySelector; 5}) => KeySelector;
This allows the ability to dynamically generate keySelectors
on runtime based on provided inputSelectors
/resultFunc
supporting key selectors composition. It overrides any provided keySelector
.
See programmatic keySelector composition example.
selectorCreator
Type: function
Default: reselect
's createSelector
An optional function describing a custom version of createSelector.
re-reselect selector instance
createCachedSelector
and createStructuredCachedSelector
return a selector instance which extends the API of a standard reselect selector.
The followings are advanced methods and you won't need them for basic usage!
selector.getMatchingSelector(selectorArguments)
Retrieve the selector responding to the given arguments.
selector.removeMatchingSelector(selectorArguments)
Remove from the cache the selector responding to the given arguments.
selector.cache
Get the cacheObject instance being used by the selector (for advanced caching operations like this).
selector.clearCache()
Clear whole selector
cache.
selector.dependencies
Get an array containing the provided inputSelectors
. Refer to relevant discussion on Reselect repo.
selector.resultFunc
Get resultFunc
for easily testing composed selectors.
selector.recomputations()
Return the number of times the selector's result function has been recomputed.
selector.resetRecomputations()
Reset recomputations
count.
selector.keySelector
Get keySelector
for utility compositions or testing.
About re-reselect
- re-reselect your whole redux state
- Understanding reselect and re-reselect
- React re-reselect: Better memoization and cache management
- Advanced Redux patterns: selectors
- Be selective with your state
- A swift developer’s React Native experience
- 5 key Redux libraries to improve code reuse
- Rematch's docs
- Redux re-reselect playground
Todo's
- Improve tests readability
- Port to native TS based on reselect v5 approach
- Find out whether
re-reselect
should be deprecated in favour ofreselect
memoization/cache options
Contributors
Thanks to you all (emoji key):

No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
29 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE.md:0
- Info: FSF or OSI recognized license: MIT License: LICENSE.md:0
Reason
1 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
Reason
dependency not pinned by hash detected -- score normalized to 2
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:36: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/ci.yml/master?enable=pin
- Warn: third-party GitHubAction not pinned by hash: .github/workflows/dependabot-auto-merge.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/toomuchdesign/re-reselect/dependabot-auto-merge.yml/master?enable=pin
- Info: 0 out of 5 GitHub-owned GitHubAction dependencies pinned
- Info: 0 out of 2 third-party GitHubAction dependencies pinned
- Info: 1 out of 1 npmCommand dependencies pinned
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: jobLevel 'contents' permission set to 'write': .github/workflows/dependabot-auto-merge.yml:12
- Warn: no topLevel permission defined: .github/workflows/ci.yml:1
- Warn: no topLevel permission defined: .github/workflows/dependabot-auto-merge.yml:1
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 30 are checked with a SAST tool
Score
5.4
/10
Last Scanned on 2025-02-03
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More