Hi,
I made a post on SO, but got no responses. I was wondering if someone here can help.
Thanks.
please refer define-selectors
I've also run into this issue - and while it's not so much a reselect issue - it would be nice if it were supported in some way. It was driving me bonkers trying to sort work out why this was failing until it occurred to me to change the order of the selector definitions. This just feels so dirty.
Without using something like this define-selectors library, or building your own, there's not a very good way around this. We're just not ever going to be able to use a variable that hasn't been defined yet.
Perhaps we can make the developer experience better by throwing more informative errors. @matthopson what did the error you were running into look like?
Edit: It would be really cool if the error told us exactly what was missing so that we don't have to pour lots of time into debugging these sorts of issues.
@jimbol I'm not sure how you'd differentiate given the error message, but perhaps an addendum to the message, and some info in the Composed Selectors docs would help clear this up from a dev perspective.
The error is something like: Selector creators expect all input-selectors to be functions, instead received the following types: [knownSelector, undefined, undefined]
Where undefined is a function declared _below_ this composed selector. So to reproduce:
const selectMembers = state => state.members
const reSelectMembersAndLocations = createSelector(
[selectMembers, selectLocations],
(members, locations) => {
// magical member mapping mayhem
}
)
const selectLocations = state => state.locations
Would result in the error with [selectMembers, undefined]
Changing selectLocations to: function selectLocations (state) { return state.locations } will work just fine. But not when declared with const _after_ declaring your composed selector. (I'm trying to be clear for anyone else stumbling through this now).
Thanks!
FWIW, I'm pretty sure this is "just" a factor of how const and let work. Anything declared with var or function() is hoisted to the top of the current scope, but anything declared with const and let does not actually exist until that line. (I believe the relevant phrase is "Temporal Dead Zone".)
So, if you define a selector later on in a file using const, but try to use it earlier, it simply will not exist yet.
It's certainly possible for createSelector to check for undefined input selectors, but this issue isn't Reselect-specific.
Yes indeed. Functions get hoisted.
console.log(typeof a); // function
function a() {}
vars names get hoisted, but they don't get defined until you reach them
console.log(typeof b); // undefined
var b = 'abcd';
const and let are not hoisted at all. This is news to me
console.log(typeof c); // Uncaught ReferenceError: c is not defined
const c = 'abcd';
This is important for the issue at hand, since using var won't hoist selectors created with createSelector.
function getSelectedIds (state) { return state.selectedIds; }
function getHash (state) { return state.hash; }
// Even though we use var,
// this line will throw since `getSelectedEntities` isnt defined until the next line
var getSelectedNames = createSelector(getSelectedEntities, (entities) => entities.map(e => e.name));
var getSelectedEntities = createSelector(getSelectedIds, getHash, (ids, hash) => ids.map(id => hash[id]);)
In other words @markerikson, you're right, this isn't a reselect issue, but a part of JS itself.
I'll go ahead and close this, since it isn't actually a Reselect bug. If someone wanted to submit a PR that adds checks for undefined inside of createSelector, that might be useful.
Most helpful comment
FWIW, I'm pretty sure this is "just" a factor of how
constandletwork. Anything declared withvarorfunction()is hoisted to the top of the current scope, but anything declared withconstandletdoes not actually exist until that line. (I believe the relevant phrase is "Temporal Dead Zone".)So, if you define a selector later on in a file using
const, but try to use it earlier, it simply will not exist yet.It's certainly possible for
createSelectorto check for undefined input selectors, but this issue isn't Reselect-specific.