I have the following selector:
const getAllAddresses = (withStartEnd) =>
createSelector(
[getAllAddressesSelector, getStartAddressSelector, getEndAddressSelector],
(all, startAddress, endAddress) => {
if (!withStartEnd) return [...Object.values(all)];
return [startAddress, ...Object.values(all), endAddress];
}
);
I noticed that the selector is re-calculating every time, event when all
, startAddress
and endAddress
do not change. If I remove the input for the selector function, to something like this:
const getAllAddresses = (
createSelector(
[getAllAddressesSelector, getStartAddressSelector, getEndAddressSelector],
(all, startAddress, endAddress) => {
return [startAddress, ...Object.values(all), endAddress];
}
)
);
Then everything works as expected and the selector does not re-calculate on every call. Seems like I missing something in the selector concept. Any help would be much appreciated.
I have the following selector:
const getAllAddresses = (withStartEnd) =>
createSelector(
[getAllAddressesSelector, getStartAddressSelector, getEndAddressSelector],
(all, startAddress, endAddress) => {
if (!withStartEnd) return [...Object.values(all)];
return [startAddress, ...Object.values(all), endAddress];
}
);
I noticed that the selector is re-calculating every time, event when all
, startAddress
and endAddress
do not change. If I remove the input for the selector function, to something like this:
const getAllAddresses = (
createSelector(
[getAllAddressesSelector, getStartAddressSelector, getEndAddressSelector],
(all, startAddress, endAddress) => {
return [startAddress, ...Object.values(all), endAddress];
}
)
);
Then everything works as expected and the selector does not re-calculate on every call. Seems like I missing something in the selector concept. Any help would be much appreciated.
Share Improve this question asked May 26, 2019 at 9:03 AsafAsaf 2,1782 gold badges25 silver badges40 bronze badges1 Answer
Reset to default 3Update:
Please refer to How do I create a selector that takes an argument?
In short: the way you did it, will work only if you pass static arguments and create a factory function outside of mapStateToProps
. For dynamic arguments it's more plex and please follow the resource I already mentioned above.
The reason your selector is recalculated each time mapStateToProps
is called is that calling getAllAddresses
will create a new instance of createSelector
and the memoization won't work.
Original answer:
In short, reselect
determines input selector changes, based on identity check ===
.
Therefore, if your input selectors always create and return a new object or array, then your selector will be recalculated each time.
In order to fix the recalculation issues:
- Make sure your input selectors always return a reference, instead of new object / array.
- Or, if a new object / array is the proper returned value, then you have to customize the equalityCheck for defaultMemoize
From the reselect
docs:
Why is my selector reputing when the input state stays the same? (please follow the link, there are great examples)
Check that your memoization function is patible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with createSelector that reputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. createSelector uses an identity check (===) to detect that an input has changed, so returning a new object on each update means that the selector will repute on each update.