change reaction api

This commit is contained in:
Yanick Champoux 2023-03-22 12:04:07 -04:00
parent 0e894b7db1
commit bde9cac053
4 changed files with 11 additions and 5 deletions

View File

@ -40,6 +40,7 @@
"prettier": "^2.7.1", "prettier": "^2.7.1",
"redux-toolkit": "^1.1.2", "redux-toolkit": "^1.1.2",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "^4.2.1",
"vitest": "0.23.1" "vitest": "0.23.1"
} }
} }

View File

@ -56,7 +56,7 @@ type ResolveActions<
}; };
type Reaction<S = any, M extends MiddlewareAPI = MiddlewareAPI> = type Reaction<S = any, M extends MiddlewareAPI = MiddlewareAPI> =
(api: M, state: S, previousState: S, unsubscribe: () => void) => void; (api: M) => (state: S, previousState: S, unsubscribe: () => void) => any;
type AugmentedMiddlewareAPI<S, A, SELECTORS> = type AugmentedMiddlewareAPI<S, A, SELECTORS> =
MiddlewareAPI<Dispatch<AnyAction>, S> & { MiddlewareAPI<Dispatch<AnyAction>, S> & {
@ -217,6 +217,8 @@ export default class Updux<
unsub = store.subscribe(() => r(unsub)); unsub = store.subscribe(() => r(unsub));
} }
(store as any).actions = this.actions;
return store as ToolkitStore< return store as ToolkitStore<
AggregateState<T_LocalState, T_Subduxes> AggregateState<T_LocalState, T_Subduxes>
@ -326,12 +328,13 @@ export default class Updux<
this.actions, this.actions,
this.selectors this.selectors
); );
const r = reaction(api);
return (unsub: () => void) => { return (unsub: () => void) => {
const state = api.getState(); const state = api.getState();
if (state === previous) return; if (state === previous) return;
let p = previous; let p = previous;
previous = state; previous = state;
reaction(api, state, p, unsub); r(state, p, unsub);
} }
} }
; ;

View File

@ -11,7 +11,7 @@ test('basic reactions', () => {
foo.addMutation(foo.actions.inc, () => (state) => state + 1); foo.addMutation(foo.actions.inc, () => (state) => state + 1);
foo.addMutation(foo.actions.reset, () => (state) => 0); foo.addMutation(foo.actions.reset, () => (state) => 0);
foo.addReaction((api, state, _previous, unsubscribe) => { foo.addReaction((api) => (state, _previous, unsubscribe) => {
if (state < 3) return; if (state < 3) return;
unsubscribe(); unsubscribe();
api.dispatch.reset(); api.dispatch.reset();
@ -53,7 +53,7 @@ test('subdux reactions', () => {
bar.addMutation(foo.actions.reset, () => (state) => 0); bar.addMutation(foo.actions.reset, () => (state) => 0);
let seen = 0; let seen = 0;
bar.addReaction((api, state, _previous, unsubscribe) => { bar.addReaction((api) => (state, _previous, unsubscribe) => {
seen++; seen++;
expect(api.actions).not.toHaveProperty('notInBar'); expect(api.actions).not.toHaveProperty('notInBar');
expect(state).toBeTypeOf('number'); expect(state).toBeTypeOf('number');

View File

@ -3,6 +3,7 @@ import { BaseActionCreator } from '@reduxjs/toolkit/dist/createAction.js';
import * as R from 'remeda'; import * as R from 'remeda';
import { Dux } from './types.js'; import { Dux } from './types.js';
import { Mutation } from './Updux.js'; import { Mutation } from './Updux.js';
import u from '@yanick/updeep-remeda';
export type MutationCase = { export type MutationCase = {
matcher: (action: Action) => boolean; matcher: (action: Action) => boolean;
@ -22,6 +23,7 @@ export function buildReducer(
// TODO defaultMutation // TODO defaultMutation
// //
const reducer = (state = initialState, action: Action) => { const reducer = (state = initialState, action: Action) => {
const orig = state;
if (!action?.type) if (!action?.type)
throw new Error('upreducer called with a bad action'); throw new Error('upreducer called with a bad action');
@ -49,7 +51,7 @@ export function buildReducer(
if (!terminal && Object.keys(subduxes).length > 0) { if (!terminal && Object.keys(subduxes).length > 0) {
// subduxes // subduxes
state = R.merge( state = u.update(
state, state,
R.mapValues(subReducers, (reducer, slice) => R.mapValues(subReducers, (reducer, slice) =>
(reducer as any)(state[slice], action), (reducer as any)(state[slice], action),