add upreducerWrapper
This commit is contained in:
parent
8314ff94ca
commit
f1b7677f0f
49
src/Updux.ts
49
src/Updux.ts
@ -11,7 +11,14 @@ import { action } from './actions';
|
||||
import { buildUpreducer } from './buildUpreducer';
|
||||
import { buildMiddleware, augmentMiddlewareApi } from './buildMiddleware';
|
||||
|
||||
import { AggregateDuxActions, AggregateDuxState, Dict } from './types';
|
||||
import {
|
||||
AggregateDuxActions,
|
||||
AggregateDuxState,
|
||||
Dict,
|
||||
ItemsOf,
|
||||
Reducer,
|
||||
Upreducer,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Configuration object typically passed to the constructor of the class Updux.
|
||||
@ -70,6 +77,28 @@ export interface UpduxConfig<
|
||||
* reaction for the mapped dux.
|
||||
*/
|
||||
mappedReaction?: Function | boolean;
|
||||
|
||||
/**
|
||||
* Wrapping function for the upreducer to provides full customization.
|
||||
* @example
|
||||
* // if an action has the 'dontDoIt' meta flag, don't do anything
|
||||
* const dux = new Updux({
|
||||
* ...,
|
||||
* upreducerWrapper: (upreducer) => action => {
|
||||
* if( action?.meta?.dontDoIt ) return state => state;
|
||||
* return upreducer(action);
|
||||
* }
|
||||
* })
|
||||
*/
|
||||
upreducerWrapper?: (
|
||||
upreducer: Upreducer<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
>
|
||||
) => Upreducer<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
>;
|
||||
}
|
||||
|
||||
export class Updux<
|
||||
@ -90,6 +119,7 @@ export class Updux<
|
||||
#reactions = [];
|
||||
#mappedSelectors = undefined;
|
||||
#mappedReaction = undefined;
|
||||
#upreducerWrapper = undefined;
|
||||
|
||||
constructor(config: UpduxConfig<TState, TActions, TSelectors, TSubduxes>) {
|
||||
this.#initial = config.initial ?? {};
|
||||
@ -130,6 +160,8 @@ export class Updux<
|
||||
this.#reactions = config.reactions ?? [];
|
||||
|
||||
this.#mappedReaction = config.mappedReaction;
|
||||
|
||||
this.#upreducerWrapper = config.upreducerWrapper;
|
||||
}
|
||||
|
||||
#memoInitial = moize(buildInitial);
|
||||
@ -171,15 +203,22 @@ export class Updux<
|
||||
);
|
||||
}
|
||||
|
||||
get upreducer() {
|
||||
get upreducer(): Upreducer<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
> {
|
||||
return this.#memoUpreducer(
|
||||
this.initial,
|
||||
this.#mutations,
|
||||
this.#subduxes
|
||||
this.#subduxes,
|
||||
this.#upreducerWrapper
|
||||
);
|
||||
}
|
||||
|
||||
get reducer() {
|
||||
get reducer(): Reducer<
|
||||
AggregateDuxState<TState, TSubduxes>,
|
||||
ItemsOf<AggregateDuxActions<TActions, TSubduxes>>
|
||||
> {
|
||||
return (state, action) => this.upreducer(action)(state);
|
||||
}
|
||||
|
||||
@ -340,7 +379,7 @@ export class Updux<
|
||||
selectors: Record<string, Function>;
|
||||
actions: AggregateDuxActions<TActions, TSubduxes>;
|
||||
} = reduxCreateStore(
|
||||
this.reducer,
|
||||
this.reducer as any,
|
||||
initial ?? this.initial,
|
||||
enhancer
|
||||
) as any;
|
||||
|
@ -1,4 +1,4 @@
|
||||
export type Action<T extends string = string, TPayload = unknown> = {
|
||||
export type Action<T extends string = string, TPayload = any> = {
|
||||
type: T;
|
||||
meta?: Record<string, unknown>;
|
||||
} & {
|
||||
|
@ -1,13 +1,18 @@
|
||||
import u from 'updeep';
|
||||
import { mapValues } from 'lodash';
|
||||
|
||||
export function buildUpreducer(initial, mutations, subduxes = {}) {
|
||||
export function buildUpreducer(
|
||||
initial,
|
||||
mutations,
|
||||
subduxes = {},
|
||||
wrapper = undefined
|
||||
) {
|
||||
const subReducers =
|
||||
Object.keys(subduxes).length > 0
|
||||
? mapValues(subduxes, ({ upreducer }) => upreducer)
|
||||
: null;
|
||||
|
||||
return (action) => (state) => {
|
||||
const upreducer = (action) => (state) => {
|
||||
if (!action?.type)
|
||||
throw new Error('upreducer called with a bad action');
|
||||
|
||||
@ -35,4 +40,6 @@ export function buildUpreducer(initial, mutations, subduxes = {}) {
|
||||
|
||||
return a(action.payload, action)(newState);
|
||||
};
|
||||
|
||||
return wrapper ? wrapper(upreducer) : upreducer;
|
||||
}
|
||||
|
13
src/types.ts
13
src/types.ts
@ -1,5 +1,16 @@
|
||||
import { Action } from './actions';
|
||||
|
||||
export type Dict<T> = Record<string, T>;
|
||||
|
||||
export type Upreducer<TState = any, TAction = Action> = (
|
||||
action: Action
|
||||
) => (state: TState) => TState;
|
||||
|
||||
export type Reducer<TState = any, TAction = Action> = (
|
||||
state: TState | undefined,
|
||||
action: Action
|
||||
) => TState;
|
||||
|
||||
export type UnionToIntersection<U> = (
|
||||
U extends any ? (k: U) => void : never
|
||||
) extends (k: infer I) => void
|
||||
@ -31,7 +42,7 @@ export type AggregateDuxState<TState, TSubduxes> = TState &
|
||||
|
||||
type DuxActionsSubduxes<C> = C extends object ? ActionsOf<C[keyof C]> : unknown;
|
||||
|
||||
type ItemsOf<C> = C extends object ? C[keyof C] : unknown;
|
||||
export type ItemsOf<C> = C extends object ? C[keyof C] : unknown;
|
||||
|
||||
export type AggregateDuxActions<TActions, TSubduxes> = TActions &
|
||||
UnionToIntersection<ActionsOf<ItemsOf<TSubduxes>>>;
|
||||
|
Loading…
Reference in New Issue
Block a user