From 55f0d5cd1384a5b0dd6e10ea144404e0f55d775d Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Fri, 21 Apr 2023 15:11:32 -0400 Subject: [PATCH 1/2] effect with actionCreator --- src/Updux.ts | 36 +++++++++++++++++++++++++++++------- src/effects.test.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/Updux.ts b/src/Updux.ts index baa5a6e..062eb31 100644 --- a/src/Updux.ts +++ b/src/Updux.ts @@ -45,10 +45,10 @@ type ResolveAction< ? ActionArg : ActionArg extends (...args: any) => any ? ActionCreatorWithPreparedPayload< - Parameters, - ReturnType, - ActionType - > + Parameters, + ReturnType, + ActionType + > : ActionCreatorWithoutPayload; type ResolveActions< @@ -56,10 +56,10 @@ type ResolveActions< [key: string]: any; }, > = { - [ActionType in keyof A]: ActionType extends string + [ActionType in keyof A]: ActionType extends string ? ResolveAction : never; -}; + }; type Reaction = ( api: M, @@ -311,8 +311,30 @@ export default class Updux< this.#defaultMutation = { mutation, terminal }; } - addEffect(effect: EffectMiddleware) { + addEffect(actionCreator: + AggregateActions, T_Subduxes>, + effect: EffectMiddleware): EffectMiddleware; + addEffect(effect: EffectMiddleware): EffectMiddleware; + addEffect(...args) { + let effect; + if (args.length === 1) { + effect = args[0]; + } + else { + const [actionCreator, originalEffect] = args; + + effect = (api) => next => { + const e = originalEffect(api)(next); + return action => { + const func = actionCreator.match(action) ? e : next; + return func(action); + } + } + } + this.#localEffects.push(effect); + + return effect; } get effectsMiddleware() { diff --git a/src/effects.test.ts b/src/effects.test.ts index 007abb4..0d93fa9 100644 --- a/src/effects.test.ts +++ b/src/effects.test.ts @@ -39,7 +39,7 @@ test('buildEffectsMiddleware', () => { expect(seen).toEqual(0); const dispatch = vi.fn(); - mw({ getState: () => 'the state', dispatch })(() => {})({ + mw({ getState: () => 'the state', dispatch })(() => { })({ type: 'noop', }); expect(seen).toEqual(1); @@ -106,5 +106,30 @@ test('subdux', () => { expect(seen).toEqual(1); }); +test('addEffect with actionCreator', () => { + const dux = new Updux({ + actions: { + foo: null, + bar: null, + }, + }); + + const next = vi.fn(); + const spy = vi.fn(); + + const mw = dux.addEffect(dux.actions.foo, (api) => (next) => (action) => + next(spy(action)) + ); + + mw({})(next)(dux.actions.bar()); + expect(next).toHaveBeenCalled(); + expect(spy).not.toHaveBeenCalled(); + + next.mockReset(); + mw({})(next)(dux.actions.foo()); + expect(next).toHaveBeenCalled(); + expect(spy).toHaveBeenCalled(); +}); + // TODO subdux effects // TODO allow to subscribe / unsubscribe effects? From 06b4bf62c4e35ea99a6f219cc9d8e5663f3f2802 Mon Sep 17 00:00:00 2001 From: Yanick Champoux Date: Fri, 21 Apr 2023 15:24:49 -0400 Subject: [PATCH 2/2] effects with function --- src/Updux.ts | 8 +++++++- src/effects.test.ts | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Updux.ts b/src/Updux.ts index 062eb31..5a1d534 100644 --- a/src/Updux.ts +++ b/src/Updux.ts @@ -314,6 +314,9 @@ export default class Updux< addEffect(actionCreator: AggregateActions, T_Subduxes>, effect: EffectMiddleware): EffectMiddleware; + addEffect(guardFunc: (action: + AggregateActions, T_Subduxes>[keyof AggregateActions, T_Subduxes>]) => boolean, + effect: EffectMiddleware): EffectMiddleware; addEffect(effect: EffectMiddleware): EffectMiddleware; addEffect(...args) { let effect; @@ -323,10 +326,13 @@ export default class Updux< else { const [actionCreator, originalEffect] = args; + const test = actionCreator.hasOwnProperty('match') ? + actionCreator.match : actionCreator; + effect = (api) => next => { const e = originalEffect(api)(next); return action => { - const func = actionCreator.match(action) ? e : next; + const func = test(action) ? e : next; return func(action); } } diff --git a/src/effects.test.ts b/src/effects.test.ts index 0d93fa9..41e63ae 100644 --- a/src/effects.test.ts +++ b/src/effects.test.ts @@ -39,7 +39,7 @@ test('buildEffectsMiddleware', () => { expect(seen).toEqual(0); const dispatch = vi.fn(); - mw({ getState: () => 'the state', dispatch })(() => { })({ + mw({ getState: () => 'the state', dispatch })(() => {})({ type: 'noop', }); expect(seen).toEqual(1); @@ -117,8 +117,35 @@ test('addEffect with actionCreator', () => { const next = vi.fn(); const spy = vi.fn(); - const mw = dux.addEffect(dux.actions.foo, (api) => (next) => (action) => - next(spy(action)) + const mw = dux.addEffect( + dux.actions.foo, + (api) => (next) => (action) => next(spy(action)), + ); + + mw({})(next)(dux.actions.bar()); + expect(next).toHaveBeenCalled(); + expect(spy).not.toHaveBeenCalled(); + + next.mockReset(); + mw({})(next)(dux.actions.foo()); + expect(next).toHaveBeenCalled(); + expect(spy).toHaveBeenCalled(); +}); + +test('addEffect with function', () => { + const dux = new Updux({ + actions: { + foo: () => {}, + bar: () => {}, + }, + }); + + const next = vi.fn(); + const spy = vi.fn(); + + const mw = dux.addEffect( + (action) => action.type[0] === 'f', + (api) => (next) => (action) => next(spy(action)), ); mw({})(next)(dux.actions.bar());