Function: buildAdapter()
buildAdapter<
State
>(): <S
,R
>(reactionsWithSelectors
) =>NewBlockAdder
<State
,WithStateSelector
<State
,S
>,ReactionsWithoutSelectors
<State
,R
&BasicAdapterMethods
<State
>>>
Defined in: src/lib/adapters/build-adapter.function.ts:110
buildAdapter
is called with an initial adapter, then can be called again and again with more objects inheriting from previous objects, until a final empty call ()
to get the final built adapter:
import { buildAdapter } from '@state-adapt/core';
import { numberAdapter } from './number.adapter';
const numberStringAdapter = buildAdapter<number>()(numberAdapter)({
// Define more selectors
})(([selectors, reactions]) => ({
// Define more state changes
}))({
// Define grouped state changes
})(); // End
The first call creates a new object, but after that, every object passed in is looped over and used to mutate the original new object.
buildAdapter takes 3 possible arguments in each call (after the first):
- A selectors object
- A function taking in a tuple of
[selectors, reactions]
and returning new reactions - A nested object defining grouped state reactions
1. Selectors
buildAdapter
provides full selector memoization and a default state
selector (after the first call). The selectors defined in the first call each receive a state object to select against. Each subsequent selector block has access to all selectors previously defined. To return all the selectors combined into an adapter, call it a final time with no parameter.
Example: Basic selectors
import { buildAdapter } from '@state-adapt/core';
const stringAdapter = buildAdapter<string>()({})({
reverse: s => s.state.split('').reverse().join(''),
})({
isPalendrome: s => s.reverse === s.state,
})();
s
is typed as an object with properties with the same names as all the selectors defined previously, and typed with each corresponding selector's return type. Internally, buildAdapter
uses a Proxy
to detect which selectors your new selector functions are accessing in order memoize them efficiently.
2. Reactions
Example: Basic Reactions
import { buildAdapter } from '@state-adapt/core';
import { numberAdapter } from './number.adapter';
const numberStringAdapter = buildAdapter<number>()(numberAdapter)({
negativeStr: s => s.negative.toString(),
})(([selectors, reactions]) => ({
setToNegative: state => selectors.negative(state),
}))();
setToNegative
becomes a reaction on numberStringAdapter
that multiplies the state by -1
(the return of selectors.negative(state)
).
Selectors used when defining new reactions must be called as functions and will not be memoized. If efficiency is critical, you might want to put the derived state in the action payload for the state change.
3. Grouped Reactions
The nested object defining grouped state reactions is for nested states. In the following example, a group state reaction called setBothNumbers
will set both coolNumber
and weirdNumber
to the same payload passed into the new setBothNumbers
reaction.
Example: Grouped Reactions
const numbersAdapter = buildAdapter<NumbersState>()({
setCoolNumber: (state, newCoolNumber: number) => ({
...state,
coolNumber: newCoolNumber,
}),
setWeirdNumber: (state, newWeirdNumber: number) => ({
...state,
weirdNumber: newWeirdNumber,
}),
})({
setBothNumbers: {
coolNumber: numberAdapter.set,
weirdNumber: numberAdapter.set,
},
})();
The new reaction's payload type will be the intersection of the payload types from the reactions used, except when one of the payloads is void
, in which case it will be ignored in the payload intersection.
Type Parameters
State
State
Returns
<
S
,R
>(reactionsWithSelectors
):NewBlockAdder
<State
,WithStateSelector
<State
,S
>,ReactionsWithoutSelectors
<State
,R
&BasicAdapterMethods
<State
>>>
Type Parameters
S
S
extends Selectors
<State
>
R
R
extends ReactionsWithSelectors
<State
, S
>
Parameters
reactionsWithSelectors
Adapter
<State
, S
, R
> = ...
Returns
NewBlockAdder
<State
, WithStateSelector
<State
, S
>, ReactionsWithoutSelectors
<State
, R
& BasicAdapterMethods
<State
>>>