4

As I compose more selectors together, I'm finding that I'm reordering where the selectors are defined. For example,

export const selectNav = state => state.nav;
export const selectPage = state => state.page;

export const selectNavAndPage = createSelector([
    selectNav,
    selectPage,
], (nav, page) => {

});

export const selectFoo = state => state.foo;

export const selectNavAndPageAndFoo = createSelector([
    selectNavAndPage,
    selectFoo,
], (navAndPage, foo) => {

});

This is a simple example, but I could not define selectNavAndPage below selectNavAndPageAndFoo. As more selectors get composed and selectors of selectors get composed, then I need to make sure all the sub-selectors are defined at the top before I use them.

Is there some way to create these selectors such that ordering doesn't matter?

epikhighs
  • 458
  • 3
  • 14

3 Answers3

2

I was worried about the same problem and I created this npm module define-selectors. This is a module that delays the definition of the selector to solve the ordering of selector definition problem and adds other features to it. It has not been stable yet, but I will use it on my project to make it stable and be improved.

For more information please go to github page and read the README and source files.

Alfred
  • 1,276
  • 11
  • 19
1

I'm pretty sure this is just related to how the ES6 const keyword works. With const, variables do not exist until that line, so if you want to reference a const variable, you need to write that code after the variable declaration. With var, all variables are hosted to the top of the scope.

So, either use var so that you can reference things out of order, or continue using const and define each function in the correct order for usage and references.

markerikson
  • 63,178
  • 10
  • 141
  • 157
  • unfortunately, changing const to var in my example will not work. The variable would be hoisted, but when createSelector() is called, then the hoisted undefined variable would be passed in. – epikhighs Apr 18 '17 at 20:47
1

If you don't mind a little extra typing, here is another approach which requires defining a 'cms' utility function that wraps the createSelector function and takes advantage of function hoisting:

import {createSelector} from 'reselect';

// create memoized selector
function cms(ctx, ...args) {
    if (!ctx.selector) ctx.selector = createSelector(...args);
    return ctx.selector;
}

// define the selectors out of order...

export function getBaz(state) {
    return cms(
        getBaz  // the function itself as context
        , getBar
        , bar => bar.baz
    )(state);
}

export function getBar(state) {
    return cms(
        getBar
        , getFoo
        , foo => foo.bar
    )(state);
}

export function getFoo(state) {
    return state.foo;
}

This is not as elegant as simply defining the selectors in order, but maybe someone else can take this idea and improve on it.

Paul Spaulding
  • 1,241
  • 1
  • 13
  • 7