subdux effects

This commit is contained in:
Yanick Champoux 2023-03-11 13:37:33 -05:00
parent 95768706fa
commit daa8421251
3 changed files with 60 additions and 8 deletions

View File

@ -6,6 +6,7 @@ import {
Action, Action,
MiddlewareAPI, MiddlewareAPI,
AnyAction, AnyAction,
Middleware,
} from 'redux'; } from 'redux';
import { import {
configureStore, configureStore,
@ -88,7 +89,7 @@ export default class Updux<
>; >;
#selectors: any; #selectors: any;
#effects: any[] = []; #localEffects: Middleware[] = [];
constructor( constructor(
config: Partial<{ config: Partial<{
@ -128,19 +129,42 @@ export default class Updux<
return this.#initial; return this.#initial;
} }
get effects() {
return [
...this.#localEffects,
...Object.entries(this.#subduxes).flatMap(
([slice, { effects }]) => {
if (!effects) return [];
return effects.map(effect => (api) => effect({
...api,
getState: () => api.getState()[slice],
}))
}
)
]
}
createStore( createStore(
options: Partial<{ options: Partial<{
initial: T_LocalState; initial: T_LocalState;
}> = {}, }> = {},
) { ) {
const preloadedState: any = options.initial ?? this.initial; const preloadedState: any = options.initial ?? this.initial;
const effects = buildEffectsMiddleware(
this.effects,
this.actions,
this.selectors,
);
const store = configureStore({ const store = configureStore({
reducer: ((state) => state) as Reducer< reducer: ((state) => state) as Reducer<
AggregateState<T_LocalState, T_Subduxes>, AggregateState<T_LocalState, T_Subduxes>,
AnyAction AnyAction
>, >,
preloadedState, preloadedState,
middleware: [this.effectsMiddleware], middleware: [effects],
}); });
const dispatch: any = store.dispatch; const dispatch: any = store.dispatch;
@ -221,11 +245,7 @@ export default class Updux<
} }
addEffect(effect: EffectMiddleware) { addEffect(effect: EffectMiddleware) {
this.#effects.push(effect); this.#localEffects.push(effect);
}
get effects() {
return this.#effects;
} }
get effectsMiddleware() { get effectsMiddleware() {

View File

@ -75,5 +75,36 @@ test('basic', () => {
expect(seen).toEqual(1); expect(seen).toEqual(1);
}); });
test('subdux', () => {
const bar = new Updux({
initial: 'bar state',
actions: { foo: 0 },
});
let seen = 0;
bar.addEffect((api) => next => action => {
seen++;
expect(api.getState()).toBe('bar state');
next(action);
});
const dux = new Updux({
initial: {
loaded: true,
},
subduxes: {
bar
},
});
const store = dux.createStore();
expect(seen).toEqual(0);
store.dispatch.foo();
expect(seen).toEqual(1);
});
// TODO subdux effects // TODO subdux effects
// TODO allow to subscribe / unsubscribe effects? // TODO allow to subscribe / unsubscribe effects?

View File

@ -1,4 +1,4 @@
import { Action, ActionCreator, Reducer } from 'redux'; import { Action, ActionCreator, Middleware, Reducer } from 'redux';
export type Dux< export type Dux<
STATE = any, STATE = any,
@ -11,6 +11,7 @@ export type Dux<
state: STATE, state: STATE,
action: ReturnType<ACTIONS[keyof ACTIONS]>, action: ReturnType<ACTIONS[keyof ACTIONS]>,
) => STATE; ) => STATE;
effects: Middleware[];
}>; }>;
type ActionsOf<DUX> = DUX extends { actions: infer A } ? A : {}; type ActionsOf<DUX> = DUX extends { actions: infer A } ? A : {};