add reactions to the updux
This commit is contained in:
parent
0f3aeff396
commit
702a3e76d4
68
src/Updux.js
68
src/Updux.js
@ -4,7 +4,7 @@ import { createStore as reduxCreateStore, applyMiddleware } from 'redux';
|
||||
|
||||
import { buildSelectors } from './selectors.js';
|
||||
import { buildUpreducer } from './upreducer.js';
|
||||
import { buildMiddleware } from './middleware.js';
|
||||
import { buildMiddleware, augmentMiddlewareApi } from './middleware.js';
|
||||
import { action, isActionGen } from './actions.js';
|
||||
|
||||
/**
|
||||
@ -21,6 +21,7 @@ export class Updux {
|
||||
#config = {};
|
||||
#selectors = {};
|
||||
#effects = [];
|
||||
#localReactions = [];
|
||||
|
||||
constructor(config = {}) {
|
||||
this.#config = config;
|
||||
@ -49,6 +50,8 @@ export class Updux {
|
||||
} else if (R.isObject(config.effects)) {
|
||||
this.#effects = Object.entries(config.effects);
|
||||
}
|
||||
|
||||
this.#localReactions = config.reactions ?? [];
|
||||
}
|
||||
|
||||
#addSubduxActions(_slice, subdux) {
|
||||
@ -171,7 +174,7 @@ export class Updux {
|
||||
};
|
||||
}
|
||||
|
||||
//this.subscribeAll(store);
|
||||
this.subscribeAll(store);
|
||||
|
||||
return store;
|
||||
}
|
||||
@ -179,6 +182,67 @@ export class Updux {
|
||||
addEffect(action, effect) {
|
||||
this.#effects = [...this.#effects, [action, effect]];
|
||||
}
|
||||
|
||||
addReaction( reaction ) {
|
||||
this.#localReactions = [ ...this.#localReactions, reaction ]
|
||||
}
|
||||
|
||||
subscribeTo(store, subscription) {
|
||||
const localStore = augmentMiddlewareApi(
|
||||
{
|
||||
...store,
|
||||
subscribe: (subscriber) =>
|
||||
this.subscribeTo(store, subscriber), // TODO not sure
|
||||
},
|
||||
this.actions,
|
||||
this.selectors
|
||||
);
|
||||
|
||||
const subscriber = subscription(localStore);
|
||||
|
||||
let previous;
|
||||
|
||||
const memoSub = () => {
|
||||
const state = store.getState();
|
||||
if (state === previous) return;
|
||||
let p = previous;
|
||||
previous = state;
|
||||
subscriber(state, p, unsub);
|
||||
};
|
||||
|
||||
let ret = store.subscribe(memoSub);
|
||||
const unsub = typeof ret === 'function' ? ret : ret.unsub;
|
||||
return {
|
||||
unsub,
|
||||
subscriberMemoized: memoSub,
|
||||
subscriber,
|
||||
};
|
||||
}
|
||||
|
||||
subscribeAll(store) {
|
||||
let results = this.#localReactions.map((sub) =>
|
||||
this.subscribeTo(store, sub)
|
||||
);
|
||||
|
||||
for (const subdux in this.#subduxes) {
|
||||
if (subdux !== '*') {
|
||||
const localStore = {
|
||||
...store,
|
||||
getState: () => store.getState()[subdux],
|
||||
};
|
||||
results.push(this.#subduxes[subdux].subscribeAll(localStore));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
unsub: () => results.forEach(({ unsub }) => unsub()),
|
||||
subscriberMemoized: () =>
|
||||
results.forEach(({ subscriberMemoized}) => subscriberMemoized()),
|
||||
subscriber: () =>
|
||||
results.forEach(({ subscriber }) => subscriber()
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const dux = (config) => new Updux(config);
|
||||
|
50
src/reactions.test.js
Normal file
50
src/reactions.test.js
Normal file
@ -0,0 +1,50 @@
|
||||
import { test, expect, vi } from 'vitest';
|
||||
|
||||
import { Updux } from './Updux.js';
|
||||
|
||||
test('basic reactions', async () => {
|
||||
const spyA = vi.fn();
|
||||
const spyB = vi.fn();
|
||||
const foo = new Updux({
|
||||
initial: { i: 0 },
|
||||
reactions: [() => spyA],
|
||||
actions: { inc: null },
|
||||
mutations: {
|
||||
inc: () => (state) => ({ ...state, i: state.i + 1 }),
|
||||
},
|
||||
});
|
||||
|
||||
foo.addReaction((api) => spyB);
|
||||
|
||||
const store = foo.createStore();
|
||||
store.dispatch.inc();
|
||||
|
||||
expect(spyA).toHaveBeenCalledOnce();
|
||||
expect(spyB).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test('subduxes reactions', async () => {
|
||||
const spyA = vi.fn();
|
||||
const spyB = vi.fn();
|
||||
const foo = new Updux({
|
||||
subduxes: {
|
||||
a: new Updux({
|
||||
initial: 1,
|
||||
reactions: [() => state => spyA(state)],
|
||||
actions: { inc: null },
|
||||
mutations: {
|
||||
inc: () => (state) => state + 1,
|
||||
},
|
||||
}),
|
||||
b: new Updux({ initial: 10, reactions: [() => spyB] }),
|
||||
},
|
||||
});
|
||||
|
||||
const store = foo.createStore();
|
||||
store.dispatch.inc();
|
||||
store.dispatch.inc();
|
||||
|
||||
expect(spyA).toHaveBeenCalledTimes(2);
|
||||
expect(spyA).toHaveBeenCalledWith(3)
|
||||
expect(spyB).toHaveBeenCalledOnce(); // the original inc initialized the state
|
||||
});
|
Loading…
Reference in New Issue
Block a user