define-selectors is a solution to this stackoverflow problem. It works based on Reselect and Re-reselect.
$ npm install define-selectors
reselect:
import { createSelector } from 'reselect'
const inputSelector1 = (state) => state.val1
const inputSelector2 = (state) => state.val2
const someSelector = createSelector([
inputSelector1,
inputSelector2,
], ( val1, val2 ) => {
// expensive calculation
return val1 + val2
})
define-selectors:
import defineSelectors from 'define-selectors'
const inputSelector1 = (state) => state.val1
const inputSelector2 = (state) => state.val2
const { someSelector } = defineSelectors({
someSelector: [[
inputSelector1,
inputSelector2,
], ( val1, val2 ) => {
// expensive calculation
return val1 + val2
}],
})
// equivalent to above
const { someSelector } = defineSelectors({
someSelector: {
inputSelectors: [
inputSelector1,
inputSelector2,
],
resultFunc: ( val1, val2 ) => {
// expensive calculation
return val1 + val2
},
},
})
import defineSelectors from 'define-selectors'
const selectNav = state => state.nav
const selectPage = state => state.page
const selectFoo = state => state.foo
const { selectNavAndPageAndFoo, selectNavAndPage } = defineSelectors({
selectNavAndPageAndFoo: [
[ 'selectNavAndPage', selectFoo ], // Note! 'selectNavAndPage' must be string type!
(navAndPage, foo) => {
return `${navAndPage}/${foo}`
},
],
selectNavAndPage: [
[ selectNav, selectPage ],
(nav, page) => {
return `${nav}/${page}`
},
],
})
const state = { nav: 'navA', page: 'pageB', foo: 'fooC' }
console.log( selectNavAndPageAndFoo(state) ) // 'navA/pageB/fooC'
define-reselect consists in just one method exported as default.
import defineSelectors from 'define-reselect'
selectors
is a object. key: selectorName, value: selectorData pairs
{
selectorName1: selectorData1,
selectorName2: selectorData2,
...
}
-
selectorData
is a very important here. it is a object or array. selectorData containsinputSelectors
,resultFunc
,resolverFunc
,cacheSize
,customSelectorCreator
.inputSelectors
,resultFunc
are required and the remainings are optional. -
selectorData(array):
[ inputSelectors, resultFunc, resolverFunc, cacheSize, customSelectorCreator ]
Note these index position. If you want to use customSelectorCreator
but don't want resolverFunc
and cacheSize
try this:
[ inputSelectors, resultFunc, void 0, void 0, customSelectorCreator ]
- selectorData(object)
{
inputSelectors: inputSelectors,
resultFunc: resultFunc,
resolverFunc: resolverFunc,
cacheSize: cacheSize,
customSelectorCreator: customSelectorCreator,
}
- inputSelectors(array): refer Reselect project. To avoid difinition ordering problem, you have to define each selector in the same
selectors
object. When you use the selector in the same selectors as inputSelector, use selectorName as thestring
type. In above example, when selectNavAndPageAndFoo is defined, it recursively go to theselectNavAndPage
selector to define this first.FOUND_CIRCULAR_REFERENCE
error occurs if a circular reference is found. - resultFunc(function): refer Reselect project
- resolverFunc(function): refer Re-reselect project
- cacheSize(number): refer my unmerged PR to reselect
- customSelectorCreator(function): refer Reselect project
Happy to PR any of the improvements you're thinking about. Thanks!