Reselect Utils
Edit page
IntroductionQuick Start
Guides
Path & Prop SelectorsBound & Adapted SelectorsStructured & Sequence SelectorsChain & Empty SelectorsComposing Key Selector CreatorMain PurposeKey Selectors Composition
Graphs
API

Composing Key Selector Creator

Main Purpose

There is a concept of Key Selector in re-reselect. It is working approach, but there are some limitations in straight forward using of this solution. Look at this example:

const state = {
persons: {
1: {
id: 1,
firstName: 'Marry',
secondName: 'Poppins',
},
2: {
id: 2,
firstName: 'Harry',
secondName: 'Potter',
},
},
};
import { createCachedSelector } from 're-reselect';
import { prop } from 'reselect-utils';
const personsSelector = (state: State) => state.persons;
const personSelector = createCachedSelector(
[personsSelector, prop<{ personId: number }>().personId()],
(persons, personId) => persons[personId],
)({
keySelector: prop<{ personId: number }>().personId(),
});
const fullNameSelector = createCachedSelector(
[personSelector],
({ firstName, secondName }) => `${firstName} ${secondName}`,
)({
keySelector: prop<{ personId: number }>().personId(),
});

As you can see, every time, when we want use personSelector, we should declare keySelector. Since 3.3.0 version re-reselect introduces special Key Selector Creator option. This option can help you reduce keySelector boiler plate. Reselect Utils offer implementation of Key Selector Creator: Composing Key Selector Creator. This implementation just merges all Key Selecters from selector dependencies and splits them by : sign. So, previous example can be rewritten next way:

import { prop, composingKeySelectorCreator } from 'reselect-utils';
const personSelector = createCachedSelector(
[personsSelector, prop<{ personId: number }>().personId()],
(persons, personId) => persons[personId],
)({
keySelector: prop<{ personId: number }>().personId(),
});
const fullNameSelector = createCachedSelector(
[personSelector],
({ firstName, secondName }) => `${firstName} ${secondName}`,
)({
keySelectorCreator: composingKeySelectorCreator,
});

But Composing Key Selector Creator don't detect props automatically, so every time, when you use some property in selector dependencies, you should declare it in Key Selector. See next example:

import { prop, composingKeySelectorCreator } from 'reselect-utils';
const fullNameSelector = createCachedSelector(
[personSelector, prop<{ prefix: string }>().prefix()],
({ firstName, secondName }, prefix) => `${prefix} ${firstName} ${secondName}`,
)({
keySelector: prop<{ prefix: number }>().prefix(),
keySelectorCreator: composingKeySelectorCreator,
});

Now fullNameSelector receives two properties: personId and prefix. It will work next way:

fullNameSelector.keySelector(state, {
personId: 1,
prefix: 'Mr.',
}); // => 'Mr.:1'
fullNameSelector.keySelector(state, {
personId: 2,
prefix: 'Ms.',
}); // => 'Ms.:2'

Key Selectors Composition

If you want use few props in selector dependencies, you can use composeKeySelectors helper:

import {
prop,
composeKeySelectors,
composingKeySelectorCreator,
} from 'reselect-utils';
const fullNameSelector = createCachedSelector(
[
personSelector,
prop<{ prefix: string }>().prefix(),
prop<{ postfix: string }>().postfix(),
],
({ firstName, secondName }, prefix, postfix) =>
`${prefix} ${firstName} ${secondName} (${postfix})`,
)({
keySelector: composeKeySelectors(
prop<{ prefix: number }>().prefix(),
prop<{ postfix: string }>().postfix(),
),
keySelectorCreator: composingKeySelectorCreator,
});
fullNameSelector.keySelector(state, {
personId: 1,
prefix: 'Mr.',
postfix: 'father',
}); // => 'Mr.:father:1'
fullNameSelector.keySelector(state, {
personId: 2,
prefix: 'Ms.',
postfix: 'sister',
}); // => 'Ms.:sister:2'