Function: joinAdapters()
joinAdapters<
ParentState
,ExcludedProps
>(): <AE
>(adapterEntries
) =>NewBlockAdder
<ParentState
,FlattendAdapters
<AE
,ParentState
> extendsobject
?S
extendsSelectors
<ParentState
> ?WithStateSelector
<ParentState
,S
<S
>> :WithStateSelector
<ParentState
,Record
<string
, (state
) =>any
>> :object
,ReactionsWithoutSelectors
<ParentState
,FlattendAdapters
<AE
,ParentState
> &BasicAdapterMethods
<ParentState
> &WithUpdateReaction
<ParentState
>>>
Defined in: src/lib/adapters/join-adapters.function.ts:221
joinAdapters creates a complex adapter from simpler adapters by taking each of their state change functions and selectors and adding them to the new adapter with more specific names to distinguish them from each other. All state reaction names have their adapter's namespaces inserted after the first word, and all selector names get prepended with their adapter's namespace.
The initial joinAdapters call returns the same thing as the buildAdapter call, so it can be called again and again with more objects inheriting from previous objects, until a final empty call ()
to get the final built adapter.
Example: Basic joinAdapters
import { joinAdapters, createAdapter } from '@state-adapt/core';
interface State {
a: number;
b: number;
}
const adapter = joinAdapters<NumbersState>()({
a: createAdapter<number>()({}),
b: createAdapter<number>()({
setTo0: state => 0,
selectors: {
negative: state => state * -1,
},
}),
})();
This is the same as:
import { createAdapter } from '@state-adapt/core';
interface State {
a: number;
b: number;
}
const adapter = createAdapter<State>()({
setA: (state, newA: number) => ({...state, a: newA}),
resetA: (state, payload: void, initialState) => ({...state, a: initialState.a}),
setBTo0: (state, payload: void) => ({...state, b: 0}),
setB: (state, newB: number) => ({...state, b: newB}),
resetB: (state, payload: void, initialState) => ({...state, b: initialState.b}),
set: (state, newState: State) => newState,
reset: (state, payload: void, initialState) => initialState,
update: (state, newState: Partial<State>) => ({...state, ...newState}),
selectors: {
a: state => state.a,
b: state => state.b,
bNegative: state => state.b * -1,
state: state => state,
},
});
Example: joinAdapters
with buildAdapters
-like syntax
import { joinAdapters, createAdapter } from '@state-adapt/core';
import { numberAdapter } from './number.adapter';
interface NumbersState {
a: number;
b: number;
}
const adapter = joinAdapters<NumbersState>()({
a: numberAdapter,
b: numberAdapter,
})({
// Selectors
total: s => s.a + s.b,
})({
// Group reactions
incrementAll: {
a: numberAdapter.increment,
b: numberAdapter.increment,
},
})(([selectors, reactions]) => ({
// More reactions
addBToA: state => ({ ...state, a: state.a + selectors.b(state) }),
addAToB: state => ({ ...state, b: state.b + selectors.a(state) }),
}))();
For more details, see buildAdapter.
Example: Auth
import { joinAdapters, createAdapter } from '@state-adapt/core';
interface AuthState {
username: string | null;
password: string | null;
isLoggedIn: boolean;
}
const authAdapter = joinAdapters<AuthState>()({
username: createAdapter<string | null>()({}),
password: createAdapter<string | null>()({}),
isLoggedIn: createAdapter<boolean>()({
login: () => true,
logout: () => false,
}),
})();
// Usage
const initialState = { username: null, password: null, isLoggedIn: false };
const newState = authAdapter.update(initialState, {
username: 'bob',
password: '1234',
});
// { username: 'bob', password '1234', isLoggedIn: false }
Example: Cookies
import { joinAdapters, createAdapter } from '@state-adapt/core';
interface CookieState {
price: number;
flavor: 'Chocolate Chip' | 'Oatmeal Raisin';
}
const cookieAdapter = joinAdapters<CookieState>()({
price: createAdapter<number>()({
selectors: {
discounted: state => state * 0.9,
},
}),
flavor: createAdapter<Flavor>()({
setToChocolateChip: () => 'Chocolate Chip',
setToOatmealRaisin: () => 'Oatmeal Raisin',
}),
})();
interface CookiesState {
favorite: CookieState;
leastFavorite: CookieState;
}
const initialCookiesState: CookiesState = {
favorite: {
price: 200,
flavor: 'Chocolate Chip',
},
leastFavorite: {
price: 190,
flavor: 'Oatmeal Raisin',
},
};
const cookiesAdapter = joinAdapters<CookiesState>()({
favorite: cookieAdapter,
leastFavorite: cookieAdapter,
})({
totalPrice: s => s.favorite.price + s.leastFavorite.price,
})({
totalPriceDiscounted: s => s.totalPrice * 0.9,
})();
// Usage
cookiesAdapter.setFavoriteToOatmealRaisin(initialCookiesState);
cookiesAdapter.setLeastFavoriteToOatmealRaisin(initialCookiesState);
const favoritePriceDiscounted =
cookiesAdapter.selectors.favoritePriceDiscounted(initialCookiesState);
const totalPrice = cookiesAdapter.selectors.totalPrice(initialCookiesState);
const totalPriceDiscounted =
cookiesAdapter.selectors.totalPriceDiscounted(initialCookiesState);
Example: Olympic Sports
import { joinAdapters, createAdapter } from '@state-adapt/core';
interface SportState {
name: string;
isOlympic: boolean;
}
const sportAdapter = joinAdapters<SportState>()({
name: createAdapter<string>()({
setToSoccer: () => 'soccer',
setToBasketball: () => 'basketball',
}),
isOlympic: createAdapter<boolean>()({
setToTrue: () => true,
setToFalse: () => false,
}),
})({
isOlympicAndSoccer: s => s.isOlympic && s.name === 'soccer',
isOlympicAndBasketball: s => s.isOlympic && s.name === 'basketball',
})({
setToOlympicSoccer: {
name: () => 'soccer',
isOlympic: () => true,
},
})();
Type Parameters
ParentState
ParentState
extends Record
<string
, any
>
ExcludedProps
ExcludedProps
extends string
= ""
Returns
<
AE
>(adapterEntries
):NewBlockAdder
<ParentState
,FlattendAdapters
<AE
,ParentState
> extendsobject
?S
extendsSelectors
<ParentState
> ?WithStateSelector
<ParentState
,S
<S
>> :WithStateSelector
<ParentState
,Record
<string
, (state
) =>any
>> :object
,ReactionsWithoutSelectors
<ParentState
,FlattendAdapters
<AE
,ParentState
> &BasicAdapterMethods
<ParentState
> &WithUpdateReaction
<ParentState
>>>
Type Parameters
AE
AE
extends AdapterEntries
<Omit
<ParentState
, ExcludedProps
>>
Parameters
adapterEntries
AE
Returns
NewBlockAdder
<ParentState
, FlattendAdapters
<AE
, ParentState
> extends object
? S
extends Selectors
<ParentState
> ? WithStateSelector
<ParentState
, S
<S
>> : WithStateSelector
<ParentState
, Record
<string
, (state
) => any
>> : object
, ReactionsWithoutSelectors
<ParentState
, FlattendAdapters
<AE
, ParentState
> & BasicAdapterMethods
<ParentState
> & WithUpdateReaction
<ParentState
>>>