defaultMutation
This commit is contained in:
parent
2e03a51e15
commit
76ccd0d14a
20
src/Updux.ts
20
src/Updux.ts
@ -15,7 +15,7 @@ import {
|
||||
import { AggregateActions, Dux } from './types.js';
|
||||
import { buildActions } from './buildActions.js';
|
||||
import { buildInitial, AggregateState } from './initial.js';
|
||||
import { buildReducer } from './reducer.js';
|
||||
import { buildReducer, MutationCase } from './reducer.js';
|
||||
|
||||
type MyActionCreator = { type: string } & ((...args: any) => any);
|
||||
|
||||
@ -61,6 +61,7 @@ export default class Updux<
|
||||
#localInitial: T_LocalState;
|
||||
#localActions: T_LocalActions;
|
||||
#localMutations: MutationCase[] = [];
|
||||
#defaultMutation: Omit<MutationCase, 'matcher'>;
|
||||
#subduxes: T_Subduxes;
|
||||
|
||||
#name: string;
|
||||
@ -111,12 +112,17 @@ export default class Updux<
|
||||
|
||||
// TODO memoize this sucker
|
||||
get reducer() {
|
||||
return buildReducer(this.initial, this.#localMutations) as any as (
|
||||
return buildReducer(
|
||||
this.initial,
|
||||
this.#localMutations,
|
||||
this.#defaultMutation,
|
||||
) as any as (
|
||||
state: undefined | typeof this.initial,
|
||||
action: Action,
|
||||
) => typeof this.initial;
|
||||
}
|
||||
|
||||
// TODO be smarter with the guard?
|
||||
addMutation<A extends Action<any>>(
|
||||
matcher: (action: A) => boolean,
|
||||
mutation: Mutation<A, AggregateState<T_LocalState, T_Subduxes>>,
|
||||
@ -142,4 +148,14 @@ export default class Updux<
|
||||
mutation,
|
||||
});
|
||||
}
|
||||
|
||||
addDefaultMutation(
|
||||
mutation: Mutation<
|
||||
Action<any>,
|
||||
AggregateState<T_LocalState, T_Subduxes>
|
||||
>,
|
||||
terminal = false,
|
||||
) {
|
||||
this.#defaultMutation = { mutation, terminal };
|
||||
}
|
||||
}
|
||||
|
@ -37,3 +37,19 @@ test('catch-all mutation', () => {
|
||||
|
||||
expect(dux.reducer(undefined, { type: 'foo' })).toEqual('got it');
|
||||
});
|
||||
|
||||
test('default mutation', () => {
|
||||
const dux = new Updux({
|
||||
initial: '',
|
||||
actions: {
|
||||
foo: 0,
|
||||
},
|
||||
});
|
||||
|
||||
dux.addMutation(dux.actions.foo, () => () => 'got it');
|
||||
|
||||
dux.addDefaultMutation((_payload, action) => () => action.type);
|
||||
|
||||
expect(dux.reducer(undefined, { type: 'foo' })).toEqual('got it');
|
||||
expect(dux.reducer(undefined, { type: 'bar' })).toEqual('bar');
|
||||
});
|
||||
|
@ -13,6 +13,7 @@ export type MutationCase = {
|
||||
export function buildReducer(
|
||||
initialState: any,
|
||||
mutations: MutationCase[] = [],
|
||||
defaultMutation?: Omit<MutationCase, 'matcher'>,
|
||||
subduxes: Record<string, Dux> = {},
|
||||
) {
|
||||
// const subReducers =
|
||||
@ -32,12 +33,20 @@ export function buildReducer(
|
||||
.filter(({ matcher }) => matcher(action))
|
||||
.forEach(({ mutation, terminal: t }) => {
|
||||
if (t) terminal = true;
|
||||
didSomething = true;
|
||||
//
|
||||
// TODO wrap mutations in immer
|
||||
state = mutation((action as any).payload, action)(state);
|
||||
});
|
||||
|
||||
// TODO defaultMutation
|
||||
if (!didSomething && defaultMutation) {
|
||||
if (defaultMutation.terminal) terminal = true;
|
||||
|
||||
state = defaultMutation.mutation(
|
||||
(action as any).payload,
|
||||
action,
|
||||
)(state);
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user