toomuchdesign / re-reselect Goto Github PK
View Code? Open in Web Editor NEWEnhance Reselect selectors with deeper memoization and cache management.
License: MIT License
Enhance Reselect selectors with deeper memoization and cache management.
License: MIT License
Is there a way to include key resolvers, for example, the way I use re-reselect is like this:
const filterByPrecedence = createCachedSelector(
getProps("documentTypes", "precedenceTitle"),
(documentTypes, precedenceTitle) =>{
return documentTypes.filter(({ precedence }) => precedence && precedence.title === precedenceTitle)
}
)(processCacheName("documentTypes", "precedenceTitle"));
in this case I take data from state and I also process the documentTypes array as string because if a new reference of the array goes to the store, the selector is recomputed.
I would like to know your opion about this.
Should we be able to specify a cache size? There's nothing stopping the cache from growing infinitely, short of calling clearCache()
, but a cache size might be a nicer way to guard against it.
There is a typo in README.md
:
Call selector with with provided arguments
I am wondering what is the best practice when my cache-key is not defined.
In my case, I use a selector argument as the cache-key, but this one can be undefined
or null
at a given time.
''
?E.g.
// Selector
const getUserById = createCachedSelector(mySelectorFn)((state, { userId }) => userId) // Use the user id as cache key
// In my component
// In some case, I render some components before my store has been hydrated
// Resulting in userId=undefined
const user = useSelector(state => getUserById(state, { userId }) // undefined
No.
Re-reselect's documentation does not reference reselect's createStructuredSelector
and therefore it is not clear whether there is an equivalent function in re-reselect, e.g., createCachedStructuredSelector
, or if there is some other recommended way to convert existing reselect structuredSelectors to re-reselect selectors, or if it is merely a "convenience" feature of reselect not requiring the explicit support of re-reselect.
Unknown. Documentation should show an example of how this libraries authors' intend structuredSelectors to be converted to re-reselect structuredSelectors.
Read documentation.
Thanks again for pinging me about re-reselect on SO.
I have implemented it in my app super easily.
I have a few points I'd be happy to discuss with you though (sorry I removed you issue layout):
the syntax is createCachedSelector(regularSelector)(keySelector)
. I'd find it more natural if it were createCachedSelector(keySelector)(regularSelector)
as createCachedSelector(keySelector)
would become the smarter createSelector
from reselect
. What do you think? I know this would be a breaking change so it might not be possible in a near future, but at least it would have been discussed. ๐
the keySelector
syntax is (state, otherParams) => {}
. But I reckon I never used the state
params here. Isn't the selector supposed to be recalculated if the state changes, hence it shouldn't be part of the key parameters, should it? Hence, shouldn't it be instead:
createCachedSelector(
(state, id) => state.data.collection,
(state, id) => id,
(collection, id) => collection.find(c => c.id === id)
)(id => id)
export default createCachedSelector(
state => state.data.collection,
collection => collection
)(() => '')
Shouldn't this be default? If I remove the () => ''
, I get an error. I know I could use the regular reselect
createSelector
method, but to uniformize my code, I'd rather user re-reselect
everywhere.
Question
Why was the support for calling createCachedSelector()
with multiple arguments dropped and what exactly does this mean?
N/A
N/A
N/A
It's more of a question on usage and clarification what i'm doing wrong. Depending on what is really happening, it might be a bug, but more likely just some additions to README.
When using re-reselect with redux the selectors always recompute. I'm able to make simplified examples work, but when integrated into a more complex scenario, caching breaks.
I made a demo here: https://codesandbox.io/s/pmmry9j70m
If you click the "Select this article" button on the same item multiple times, the selector is recalculated.
Some background:
The buttons dispatch a thunk action that sets the selectedArticle
โ an object of multiple ids โ in the state. This object is then retrieved in the connected 'App.js' and fed as props into the getArticle selector.
My current hypothesis is that the selectors recompute due to the state change in selectedArticle
.
If you click the "Select this article" button on the same item multiple times, the selector should be pulled from cache, as the return value of the key resolver function did not change.
(If the buttons don't work, you may have to reload the sandbox)
From the readme:
resolverFunction is a function which receives the same arguments of your inputSelectors and must return a string or number.
If my cacheObject
uses a Map
instead, will re-reselect
work correctly if I return an object instead of a string|number
?
In the docs example is mentioned a code passing the state object in the first argument:
const getPieceOfData = createCachedSelector(
state => state,
(state, itemId) => itemId,
(state, itemId, dataType) => dataType,
(state, itemId, dataType, otherArg) => otherArg,
(state, itemId, dataType, otherArg) => expensiveComputation(state, itemId, dataType, otherArg),
)(
(state, itemId, dataType) => dataType, // Memoize by dataType
);
Unfortunatly I couldn't reproduce this behavior and created a little test example.
It assumes we are using immutable js
const mySelector = createCachedSelector(
state => state,
state => state.foo,
state => state.bar,
(state, foo, bar) => {
console.log('called');
return foo + bar;
})(state => 'justString');
// Selector is called when the state is changed only
// But if the state is changed it means it's a new object.
const res = mySelector({foo: 'foo', bar: 'bar'})
The selector function is not cached here and console.log always logs logged. Do I do anything wrong? or maybe it is impossible without custom cacheCreator?
Hi,
I have a problem with the way we can remove selectors from a cache object.
For example, in my code, the keys under which my selectors are stored, are generated using a function and are following a specific pattern (number(:number)*). I would like to remove from the cache every selector stored under a key starting with a "1".
The problem is, that I cannot use selector.getMatchingSelector
because it uses the resolver
instead of directly checking if _cache
has a selector stored under a specific string.
I found a way to counter that by adding this function to the createCachedSelector
function:
selector.getCache = () => {
return cache._cache;
};
and by removing manually in my code every selector stored under a key starting with a "1".
But it would be much cleaner if something similar was implemented directly in your cache objects.
So my question is the next, would it be possible to add a function which removes all the selectors of a cache object that are stored under a specific key pattern ?
If not, could you at least add a function to createCachedSelector
which allows us to get the _cache
of a cache object (like the one I had to add).
Feel free to let me know, if I'm not being clear enough !
Hi @toomuchdesign, thank you for creating this library! I was wondering if there are any recommendations around debugging selectors to make sure that the cache is working, and to see what might be causing changes?
I came across https://github.com/kbrownlees/reselect-change-memoize and was wondering if you've considered a similar utility for re-reselect
which provides callback when new objects are added to cache or when something is used from cache?
First off, I love this library!
I have a case where I need to pass a custom equalityCheck
(performing a shallow check on an array vs the default reference check). The problem that I'm facing is that when composing my re-reselect with a reselect selector that performs the custom equalityCheck
, I lose all of the performance benefits of re-reselect in the first place (as the reselect selector has a cache size of 1). Example:
// Custom equality check function
const shallowArrayEqualityCheck = (currentVal, previousVal) => {
if (currentVal.length !== previousVal.length) {
return false
}
const length = currentVal.length
for (let i = 0; i < length; i++) {
if (currentVal[i] !== previousVal[i]) {
return false
}
}
return true
}
// Selector creator that uses my custom equalityCheck function
const createShallowEqualSelector = createSelectorCreator(
defaultMemoize,
shallowArrayEqualityCheck,
)
// Using the selector creator to fetch messages and memoize correctly (using shallow check)
const messagesSelector = createShallowEqualSelector(
(state, chatroomId) => state.chatrooms[chatroomId].messages.map(messageId => getMessage(state, messageId)),
messages => messages,
)
// Use cached selector to cache based on chatroom
const messagesCachedSelector = createCachedSelector(
messagesSelector,
messages => messages,
)(
(state, chatroomId) => chatroomId,
)
Ultimately, I wish that I could pass in an equalityCheck to the cached selector, which would remove this issue!
Any thoughts/tips/ideas would be much appreciated!
Hi, and thanks for this handy library.
It looks like the selectorCreator
parameter is missing from the typings.
API Documentation:
reReselect([reselect's createSelector arguments])(resolverFunction, selectorCreator = selectorCreator)
(This should maybe be replaced with createCachedSelector in the doc to avoid confusion)
Typing:
export default function createCachedSelector<S, R1, T> (
selector: Selector<S, R1>,
combiner: (res: R1) => T
): OutputCachedSelector<S, T, (res: R1) => T>;
export type OutputCachedSelector<S, R, C> = (resolver: Resolver<S>) => OutputSelector<S, R, C> & {
getMatchingSelector: (state: S, ...args: any[]) => OutputSelector<S, R, C>;
removeMatchingSelector: (state: S, ...args: any[]) => void;
clearCache: () => void;
resultFunc: C;
};
Thanks again, and tell me if I am missing something.
import createCachedSelector from 're-reselect';
import { createSelector } from 'reselect';
import { orderBy } from 'lodash/collection';
const entitiesSelector = createSelector(
selectGlobal,
(state) => state.get('entities')
);
const pathArgSelector = (state, { path }) => path;
const entitiesPathSelector = createSelector(
entitiesSelector,
pathArgSelector,
(entities, path) => entities.get(path)
);
const sortBySelector = (state, { sortBy }) => sortBy;
const sortOrderSelector = (state, { sortOrder }) => sortOrder;
const entitiesSortedSelector = createCachedSelector(
entitiesPathSelector,
sortBySelector,
sortOrderSelector,
(entities, sortBy, sortOrder) => {
const cacheKey = `${entities.hashCode()}:${sortBy}:${sortOrder}`;
console.log('resolver', cacheKey); // resolver -181045611:id:desc
console.log('no cache for ', sortBy, sortOrder); // no cache for id desc
return orderBy(entities.toList().toJS(), getSortIteratee(sortBy), sortOrder);
}
)((entities, { sortBy, sortOrder }) => {
// NOTE here I'm actually getting passed my original state object!
const cacheKey = `${entities.hashCode()}:${sortBy}:${sortOrder}`;
console.log('cached selector', cacheKey); // cached selector 403733751:id:desc
return cacheKey;
})
Called like so in container.
const mapStateToProps = (state, props) => ({
entities: entitiesSortedSelector(state, {
path: props.entities, // ~ 'posts'
sortBy: props.sortBy || EntityQuery.defaultProps.sortBy,
sortOrder: props.sortOrder || EntityQuery.defaultProps.sortOrder,
}),
});
First off, this lib has breathed fresh air into my app. I am functional programming nube, so I tend to stumble through over-simplified examples. I have some simple, cached selectors wired up by following the examples in your docs. They look like this:
const getAllData = state => state.sliceX;
const getSliceXByID = createCachedSelector(
getAllData,
(state, sliceXid)=> sliceXid,
(allData, sliceXid) => {
...get stuff from allData using slice X ID
}
)(
(state, sliceXid) => sliceXid
)
On one particular nasty view, I need to merge, transform, and aggregate two slices of state. Each slice has a selector with the calling convention above--that works well elsewhere in the app: getSliceXByID( xID ) and getSliceYByID( yID). I can't wrap my brain around the syntax of composing a new selector from these two. The existing example that shows the re-reselect version of the reselect visibility derive data from the same slice of state keyed by the same id. I need something showing disparate state slices:
const getExpensiveMorphation = createCachedSelector(
getSliceXByID,
getSliceYByID,
{..I get lost in the weeds here}
)(
(state, sliceXid, sliceYid) =>...computed compound key of X and Y id. (this part I understand).
)
I notice the array [] input in the example and suspect that I need to keep that in play.
In the typescript definitions, line 29, getMatchingSelector: (state: S, ...args: any[])
returns ParametricSelector<S, P, R>;
My tests (which are passing successfully) are expecting an OutputParametricSelector
with recomputations
and resetcomputations
functions on them. It will be great to change the definition to
getMatchingSelector: (state: S, ...args: any[]) => OutputParametricSelector<S, P, R, any>;
Using any
is not the best solution but it definitely is better than using ParametricSelector
const getSelectedCls = createCachedSelector(
props => props.a === props.b,
bol => {
// Do what I want to do
}
)(
props => props.a === props.b
)
getSelectedCls(props); // There is no work
Great lib -- seems like it should address a pain point in my app nicely.
like what's mentioned in https://github.com/reactjs/reselect#q-how-do-i-test-a-selector, i'd like to be able to test that my cached selectors are working like I expect.
given the example code from the readme:
const cachedSelector = createCachedSelector(
(A, B, someArg) => expensiveComputation(A, B, someArg}),
)(
(state, someArg) => someArg,
);
const fooSelector = cachedSelector(state, 'foo');
const barSelector = cachedSelector(state, 'bar');
I guess the API could look like:
cachedSelector.recomputations(state, 'foo')
What do you think?
The current typing for CreateSelectorInstance
is:
export type CreateSelectorInstance = typeof createSelector;
reselect from 4.1.0 has changed the type as the defaultMemo
ized createSelector
adds a clearCache()
(not to be confused with re-reselect's createCachedSelector(...).clearCache()
). However custom selectors via reselect's createSelectorCreator
, or even just custom selectors without using reselect don't necessarily have this method.
selectorCreator
type shouldn't be tied to reselect's createSelector
type, or be more lenient.
createCachedSelector(
(state) => state.foo,
(state, id) =>id,
(foo, id) => foo[id],
{
keySelector: (foo, id) => id,
selectorCreator: createSelectorCreator((func) => func),
}
selectorCreator
key: Property 'clearCache' is missing in type '((state: {}) => any) & OutputSelectorFields<(...args: any[]) => any> & { readonly length: number; [Symbol.hasInstance]: (value: any) => boolean; toString: () => string; ... 6 more ...; caller: Function; }' but required in type '{ clearCache: () => void; }'.ts(2322)
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are awaiting their schedule. Click on a checkbox to get an update now.
@babel/core
, @babel/preset-env
).github/workflows/ci.yml
actions/checkout v4
actions/setup-node v4
package.json
@babel/core ^7.24.4
@babel/preset-env ^7.24.4
@rollup/plugin-babel ^6.0.4
@types/jest ^29.5.12
all-contributors-cli ^6.26.1
babel-jest ^29.7.0
jest ^29.7.0
lint-staged ^15.2.2
prettier ^3.2.5
reselect ^5.1.0
rimraf ^5.0.5
rollup ^4.17.2
rollup-plugin-copy ^3.5.0
simple-git-hooks ^2.11.1
ts-jest ^29.1.2
typescript ^5.4.5
reselect ^5.0.0
.nvmrc
node 20
A lot of users stumbled upon the question of which arguments are actually provided to keySelector
function.
Currently they receive the same arguments as the inputSelectors
and the selector itself, but it's easy to mistakenly think that they receive same arguments as resultFunc
(which are the result of inputSelectors
), instead.
See these threads:
Given that this problem could be alleviated with a better documentation, I'd like to better understand pros and cons of adding an option to provide keySelectors
with resultFunc
results as proposed here by @mbellman.
I'd like to use object as a param of a selector
I found this page and looks like what I need link But I can't seem to be able to get it to work.
const keySelector = (state, params) => JSON.stringify(params)
const selectData = createCachedSelector(
selectState,
(data, params) => params, // params is an object
(data, params) => {
const result = something // compute
return result
},
)({
keySelector,
cacheObject: new LruObjectCache({ cacheSize: 5 }),
})
I also tried
const selectData = createCachedSelector(
selectState,
(datae, params) => params,
(data, params) => {
const result = something // compute
return result
},
)((state, params) => JSON.stringify(params))
Both of the above are recomputing each time. What am I missing?
Can you please provide an example in the documentation?
Many thanks!
This library appears to be exactly what we need, but I can't get it to cache a thing. I'd love to know what I'm doing wrong as I'm pretty sure I've followed the docs correctly.
Container
const mapStateToProps = (state, props) => ({
pagedEntities: entitiesPagedSelector(state, {
path: props.entities,
perPage: props.perPage || EntityQuery.defaultProps.perPage,
currentPage: props.currentPage || EntityQuery.defaultProps.currentPage,
sortBy: props.sortBy || EntityQuery.defaultProps.sortBy,
sortOrder: props.sortOrder || EntityQuery.defaultProps.sortOrder,
}),
});
function mapDispatchToProps(dispatch, props) {
return {
componentWillMount: () => {
dispatch(loadEntitiesIfNeeded(props.entities));
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(EntityQuery);
Selectors
const entitiesPathSelector = (state, { path }) =>
state.getIn(['global', 'entities', path]);
const entitiesListSelector = createCachedSelector(
entitiesPathSelector,
pathArgSelector,
(entities, { path }) => {
console.log('no cache for entitiesListSelector', path)
return entities.toList()
}
)((entities, { path }) => {
console.log('entitiesListSelector cache is:', path);
return path;
});
const entitiesArraySelector = createCachedSelector(
entitiesListSelector,
pathArgSelector,
(entitiesList, { path }) => {
console.log('no cache for entitiesArraySelector', path);
return entitiesList.toJS();
}
)((_, { path }) => {
console.log('entitiesArraySelector cache is:', path);
return path;
});
const entitiesSortedSelector = createCachedSelector(
entitiesArraySelector,
sortBySelector,
(entities, { sortBy, sortOrder }) => {
console.log('no cache for entitiesSortedSelector', sortBy, sortOrder);
return orderBy(entities, getSortIteratee(sortBy), sortOrder);
}
)((entities, { path, sortBy, sortOrder }) => {
console.log('entitiesSortedSelector cache is: ', path, sortBy, sortOrder);
return `${path}${sortBy}${sortOrder}`
});
const entitiesPagedSelector = createCachedSelector(
entitiesSortedSelector,
pagingSelector,
(entities, { currentPage, perPage }) => {
const length = entities.length;
const totalPages = Math.ceil(Math.max(length, 0) / perPage);
const pageNum = Math.min(currentPage, totalPages);
const offset = (pageNum - 1) * perPage;
const end = offset + perPage;
const haveNextPage = end < entities.length;
const havePrevPage = pageNum > 1;
const page = slice(entities, offset, end);
console.log('no cache for pagedSelector ' + offset);
return {
page,
havePrevPage,
haveNextPage,
totalPages,
currentPage,
perPage,
};
}
)((entities, { path, perPage, currentPage, sortBy, sortOrder }) => {
//console.log(entities) // also this is a Map here but an array above !!
const cache = `${path}:${perPage}:${currentPage}`;
console.log('pagedSelector cache is: ', cache);
return cache
});
Nothing caching
Hey I've posted two dumb issues today, lets go for three. ;)
Is this on the right track?
const entitiesSortedSelector = createCachedSelector(
entitiesPathSelector,
sortBySelector,
sortOrderSelector,
(entities, sortBy, sortOrder) =>
orderBy(entities.toList().toJS(), getSortIteratee(sortBy), sortOrder);
)((state, { path, sortBy, sortOrder }) => {
const entities = entitiesPathSelector(state, { path });
return `${entities.hashCode()}:${sortBy}:${sortOrder}`;
});
I initially hoped that the resolver function would recieve the same args as the resolved function ( issue #2), if it doesn't then I really want to check that I'm dealing with the same entities collection here ( path param alone isn't enough )
Is the code above a correct path to take ?
I noticed a huge performance hit in my project and tracked it down to a createCachedSelector
that was constantly re-evaluating.
This createCachedSelector
is unique to my other well behaving selectors in that it uses a generated cacheKey
from another selector.
((state, props) => {
const token = selectEntityItemAssetNamesToken(state, props);
return token;
});
The token that returns is a base64 hash string. here is an example:
"bWVjaHNuaXBlci1oYW5kcy1IZWFkLW1lY2hzbmlwZXItaGFuZHMtQ2hlc3QtbWVjaHNuaXBlci1oYW5kcy1Db3JlLW1lY2hzbmlwZXItaGFuZHMtV2Fpc3QtbWVjaHNuaXBlci1oYW5kcy1TaG91bGRlckwtbWVjaHNuaXBlci1oYW5kcy1CaWNlcEwtbWVjaHNuaXBlci1oYW5kcy1Bcm1MLW1lY2hzbmlwZXItaGFuZHMtSGFuZEwtbWVjaHNuaXBlci1oYW5kcy1TaG91bGRlclItbWVjaHNuaXBlci1oYW5kcy1CaWNlcFItbWVjaHNuaXBlci1oYW5kcy1Bcm1SLW1lY2hzbmlwZXItaGFuZHMtSGFuZFItbWVjaHNuaXBlci1oYW5kcy1UaGlnaEwtbWVjaHNuaXBlci1oYW5kcy1TaGluTC1tZWNoc25pcGVyLWhhbmRzLUZvb3RMLW1lY2hzbmlwZXItaGFuZHMtVGhpZ2hSLW1lY2hzbmlwZXItaGFuZHMtU2hpblItbWVjaHNuaXBlci1oYW5kcy1Gb290Ui1tZWNoc25pcGVyLWhhbmRzLUJhY2tQYWNr"
I've confirmed that these tokens are constants and not mutating.
If I change this selector to return a smaller key it caches correctly and does not re evaluate.
((state, props) => {
return props.entityId;
});
further more I can reproduce the issue with a static token like:
((state, props) => {
const token = "bWVjaHNuaXBlci1oYW5kcy1IZWFkLW1lY2hzbmlwZXItaGFuZHMtQ2hlc3QtbWVjaHNuaXBlci1oYW5kcy1Db3JlLW1lY2hzbmlwZXItaGFuZHMtV2Fpc3QtbWVjaHNuaXBlci1oYW5kcy1TaG91bGRlckwtbWVjaHNuaXBlci1oYW5kcy1CaWNlcEwtbWVjaHNuaXBlci1oYW5kcy1Bcm1MLW1lY2hzbmlwZXItaGFuZHMtSGFuZEwtbWVjaHNuaXBlci1oYW5kcy1TaG91bGRlclItbWVjaHNuaXBlci1oYW5kcy1CaWNlcFItbWVjaHNuaXBlci1oYW5kcy1Bcm1SLW1lY2hzbmlwZXItaGFuZHMtSGFuZFItbWVjaHNuaXBlci1oYW5kcy1UaGlnaEwtbWVjaHNuaXBlci1oYW5kcy1TaGluTC1tZWNoc25pcGVyLWhhbmRzLUZvb3RMLW1lY2hzbmlwZXItaGFuZHMtVGhpZ2hSLW1lY2hzbmlwZXItaGFuZHMtU2hpblItbWVjaHNuaXBlci1oYW5kcy1Gb290Ui1tZWNoc25pcGVyLWhhbmRzLUJhY2tQYWNr";
return token;
});
Not so much a bug as an unexpected behavior.
Using the default cache strategy, calling a selector with arguments that result in a null
cache key will cause the selector to short-circuit and return undefined
, totally circumventing the actual selector code. A warning is printed to the console noting that null
is an invalid cache key.
I would expect to be able to handle a null
value in the body of my selector, but I can't. This is particularly pernicious when I'm already returning non-undefined default values (e.g. an empty list) in error cases and assuming the default value's properties (e.g. calling map
on the result of the selector function).
Example code:
const getCollectionById = createCachedSelector(
state => state.collections,
(state, collectionId) => collectionId,
(collections, collectionId) => collections[collectionId] || []
)((state, collectionId) => collectionId);
// ...
// state is { collections: { a: ['thing1', 'thing2'] } }
const yellCollection = id => getCollectionById(state, id).map(thing => thing.toUpperCase());
const yelledB = yellCollection("b"); // expect [], but get an error for trying to map undefined
null
be an eligible cache key in the default cache strategy (it's a little icky, but it does work)In the docs, there's a section about wrapping my existing selector with re-reselect, but I'd argue that instead of showing how to wrap an existing selector, it's merely showing how to convert a reselect
selector to a re-reselect
selector.
But now I wanna know, is it possible to compose a reselect
selector into createCachedSelector
?
bug
TS typings for isValidCacheKey should take an argument
isValidCacheKey('string') should not give a type error
import createCachedSelector from 're-reselect';
type State = {
id: string,
thing: string
}
const baseSelector = (state: State) => state;
const resolver = (state: State) => state.id
const cachedSelector = createCachedSelector(baseSelector, (state) => state.thing)(resolver);
cachedSelector({
id: '1',
thing: 'thing1'
})
const cache = cachedSelector.cache;
cache.isValidCacheKey('1') // Type Error: Expected 0 arguments but got 1;
I lost some time figuring out that the resolverFunction
can return a string and allow this:
createCachedSelector(
...
)((state, props) => `${props.arg1}:${props.arg2}`)
I even wrote a patch to allow the resolverFunction
to return an array before realizing this, and feeling dumb...
It would be nice to have an example illustrating this case in the documentation :)
bug
Passing types to the example with multiple arguments from the docs leads to type errors.
No type errors.
Assign ts types to createCachedSelector, like:
const getPieceOfData = createCachedSelector<StateType, StateType, ItemIdType, DataTypeType, CombinerReturnType>(
state => state, // selector1: ok
(state, itemId) => itemId, // selector2: is not assignable to type Selector because it has more than one argument.
(state, itemId, dataType) => dataType, // selector3: same issue as selector2
(state, itemId, dataType) => expensiveComputation(state, itemId, dataType)
)(
(state, itemId, dataType) => dataType // Use dataType as cacheKey
);
Manually changing the Selector type from
export type Selector<S, R> = (state: S) => R;
to
export type Selector<S, R> = (state: S ,...args: any[]) => R;
would fix the issue.
Maybe a bug?
Type error when calling createStructuredCachedSelector
without type parameters:
Typescript fails to infer the type parameters:
const state = { a: 1, b: "asdf " };
type State = typeof state;
const mySelectorA = (state: State) => state.a;
const mySelectorB = (state: State) => state.b;
const structuredSelector = createStructuredCachedSelector({
x: mySelectorA,
y: mySelectorB,
})((s: State) => "asdf");
/*
No overload matches this call.
Overload 2 of 2, '(selectors: { x: ParametricSelector<unknown, unknown, number>; y: ParametricSelector<unknown, unknown, string>; }): OutputParametricCachedSelector<unknown, unknown, { x: number; y: string; }, (...args: (string | number)[]) => { x: number; y: string; }, ParametricSelector<unknown, unknown, string | number>[]>', gave the following error.
Type '(state: { a: number; b: string; }) => number' is not assignable to type 'ParametricSelector<unknown, unknown, number>'.
Types of parameters 'state' and 'state' are incompatible.
Type 'unknown' is not assignable to type '{ a: number; b: string; }'.
Overload 2 of 2, '(selectors: { x: ParametricSelector<unknown, unknown, number>; y: ParametricSelector<unknown, unknown, string>; }): OutputParametricCachedSelector<unknown, unknown, { x: number; y: string; }, (...args: (string | number)[]) => { x: number; y: string; }, ParametricSelector<unknown, unknown, string | number>[]>', gave the following error.
Type '(state: { a: number; b: string; }) => string' is not assignable to type 'ParametricSelector<unknown, unknown, string>'.
Types of parameters 'state' and 'state' are incompatible.
Type 'unknown' is not assignable to type '{ a: number; b: string; }'.
*/
Specifying the type parameters explicitly works:
const state = { a: 1, b: "asdf " };
type State = typeof state;
const mySelectorA = (state: State) => state.a;
const mySelectorB = (state: State) => state.b;
const structuredSelector = createStructuredCachedSelector<
State,
{ x: ReturnType<typeof mySelectorA>; y: ReturnType<typeof mySelectorB> }
>({
x: mySelectorA,
y: mySelectorB,
})((s: State) => "asdf");
Are the type parameters supposed to be inferred or explicitly defined? createCachedSelector
infers the type parameters so I'm not sure if this is a bug or not, and the documentation doesn't clarify this.
I am reporting a bug.
createCachedSelector
resolver function does not receive same arguments as the final selector function.
createCachedSelector
resolver function should receive same arguments as the final selector function.
Check the example in here: https://codesandbox.io/s/w06x9moxnk
Nothing serious here, there is a small copy/pasta fail in the README, in the How do I test a re-reselect selector?
paragraph.
export const getMyData = createCachedSelector(
selectorA,
selectorB,
(A, B) => doSomethingWith(A, B),
)(
(state, arg1) => arg1, // Use arg2 as cache key
);
A bug.
It is not possible to pass an options object to createCachedSelector
as you can with createSelector
.
I currently use createSelector
with following options:
{
memoize: lruMemoize,
memoizeOptions: {
equalityCheck: (a: unknown, b: unknown) => {
if (typeof a === 'function' && typeof b === 'function') {
return true;
}
return referenceEqualityCheck(a, b);
}
}
}
I can pass an options object to createCachedSelector
just as with createSelector
.
The following is not possible:
createCachedSelector(...selectors,
// This argument causes a Typescript and runtime error
{
memoize: lruMemoize,
memoizeOptions: {
equalityCheck: (a: unknown, b: unknown) => {
if (typeof a === 'function' && typeof b === 'function') {
return true;
}
return referenceEqualityCheck(a, b);
},
},
}
)((input) => input.cacheKey);
This is a nice little library! It would be awesome if someone who knows enough typescript could add a typings file for typescript users. I have some interest in trying it out in my Angular/ngrx project, but that would work more smoothly if typings were available.
Hi,
This seems great, but for the slow among us, some examples in the documentation would be nice:
Thanks so much!
Do I need to ensure that the cache key is unique for a selector, or for the whole application ?
Seems to be per selector, so I could create two keys that are the same for different selectors I think ...
I'd like to set the cacheKey using not only the input args, but also using selector functions. I can't find any way to do that. Trying to use anything besides input args seems to result in undefined
Sorry this question isn't very well formed. I find this library amazing, but I have trouble conceptualizing about it after using it only twice several months ago.
<Resizable
defaultSize={{
width: 'auto',
height: 'auto',
}}
className="resizable-component"
>
<AceEditor
width="100%"
height="100%"
mode="html"
theme="monokai"
id={id}
value={typeof value === 'undefined' ? '' : value}
placeholder={placeholder}
readOnly={false}
focus={autofocus}
onBlur={
onBlur && (event => onBlur(id, event.target.value))
}
onFocus={
onFocus &&
(event => onFocus(id, event.target.value))
}
onChange={_onChange}
wrapEnabled={true}
fontSize={14}
showPrintMargin={true}
showGutter={true}
maxLines={400}
minLines={8}
highlightActiveLine={true}
setOptions={{
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: false,
showLineNumbers: true,
tabSize: 2,
}}
/>
</Resizable>
I need to resize once to get Ace editor display.
I'm probably misunderstanding, but it seems like what the readme example calls argument 2 is really argument 3?
In this example the second argument of the selector is used as cache key.
Wouldn't the second argument to the generated selector here be B
though, and not someArg
?
const cachedSelector = createCachedSelector(
// Set up your Reselect selector as normal:
// reselect inputSelectors:
selectorA,
selectorB,
(state, someArg) => someArg,
// reselect resultFunc:
(A, B, someArg) => expensiveComputation(A, B, someArg),
)(
/*
* Now it comes the re-reselect caching part:
* declare a resolver function, used as mapping cache key.
* It takes the same arguments as the generated selector
* and must return a string or number (the cache key).
*
* A new selector will be cached for each different returned key
*
* In this example the second argument of the selector is used as cache key
*/
(state, someArg) => someArg,
);
Bug
...
In TS, import and require syntax give difference behaviors
...
both syntax should function the same or at least it should be better with import syntax
...
const selectObjectByCommands = createCachedSelector(
(state: any) => state.array,
(array: any[]) => array,
)({
keySelector: (_state: any, commandNames: string[]) => {
return commandNames.join('_') : '';
},
selectorCreator: createShallowObjectEqualSelector,
});
let commandNames: string[] = ['text1', 'text2', 'text3'];
Things work.
The function call becomes not valid and got complaint :
Expected 1 arguments, but got 2.
If called with:
selectObjectByCommands({ array: output });
Program crashes.
Error:
Uncaught TypeError: Cannot read property 'createSelector' of undefined
at dist/index.js:26
'reselect' is added as window.Reselect
. But re-reselect gets 'reselect' by window.reselect
.
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: Cannot find preset's package (github>whitesource/merge-confidence:beta)
bug
When a selectors of a structured cached selector has an optional argument, typescript gives "unexpected argument error" when the structured cached selector is called with that optional argument.
TypeScript should not give error (I think)
createStructuredCachedSelector
with all its selectors having two parameters. The second parameter is optional for all of them.Example:
import { createStructuredCachedSelector } from 're-reselect';
type State = {
itemCounts: {
[key: string]: number,
}
};
const itemCountSelector = createStructuredCachedSelector({
allItemCounts: (state: State) => state,
// Notice that the second argument is optional
singleItemCount: (state: State, itemId?: string) => (itemId ? state.itemCounts[itemId] : null),
})(
(_state, itemId?: string) => itemId,
);
const state: State = {
itemCounts: {
item1: 2,
item2: 2,
},
};
// This does not give error
itemCountSelector(state);
// This gives an error - "Expected 1 arguments, but got 2"
itemCountSelector(state, 'item1');
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.