subscription within a subscription
This commit is contained in:
parent
c1c1edf588
commit
912ea85edc
79
src/Updux.js
79
src/Updux.js
@ -15,7 +15,19 @@ import {
|
||||
|
||||
function _subscribeToStore(store, subscriptions) {
|
||||
for (const sub of subscriptions) {
|
||||
const subscriber = sub(store);
|
||||
const subscriber = sub({
|
||||
...store,
|
||||
subscribe(subscriber) {
|
||||
let previous;
|
||||
const unsub = store.subscribe(() => {
|
||||
const state = store.getState();
|
||||
if (state === previous) return;
|
||||
let p = previous;
|
||||
previous = state;
|
||||
subscriber(state, p, unsub);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
let unsub = store.subscribe(() => subscriber(store.getState(), unsub));
|
||||
}
|
||||
@ -31,7 +43,12 @@ const sliceSubscriber = (slice, subdux) => (subscription) => (store) => {
|
||||
subdux.selectors
|
||||
);
|
||||
|
||||
return (state, unsub) => subscription(localStore)(state[slice], unsub);
|
||||
return (state, previous, unsub) =>
|
||||
subscription(localStore)(
|
||||
state[slice],
|
||||
previous && previous[slice],
|
||||
unsub
|
||||
);
|
||||
};
|
||||
|
||||
const memoizeSubscription = (subscription) => (store) => {
|
||||
@ -67,13 +84,12 @@ export class Updux {
|
||||
constructor(config) {
|
||||
this.#initial = config.initial ?? {};
|
||||
this.#subduxes = config.subduxes ?? {};
|
||||
if( config.actions ) {
|
||||
for (const [ type, actionArg ] of Object.entries(config.actions)) {
|
||||
if( typeof actionArg === 'function' && actionArg.type ) {
|
||||
if (config.actions) {
|
||||
for (const [type, actionArg] of Object.entries(config.actions)) {
|
||||
if (typeof actionArg === 'function' && actionArg.type) {
|
||||
this.#actions[type] = actionArg;
|
||||
}
|
||||
else {
|
||||
this.#actions[type] = action(type,actionArg)
|
||||
} else {
|
||||
this.#actions[type] = action(type, actionArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,16 +119,7 @@ export class Updux {
|
||||
#memoMiddleware = moize(buildMiddleware);
|
||||
|
||||
get subscriptions() {
|
||||
const subscriptions = [...this.#subscriptions].map((s) =>
|
||||
memoizeSubscription(s)
|
||||
);
|
||||
|
||||
return [
|
||||
...subscriptions,
|
||||
...map(this.#subduxes, (v, k) =>
|
||||
v.subscriptions.map(sliceSubscriber(k, v))
|
||||
).flat(),
|
||||
];
|
||||
return this.#subscriptions;
|
||||
}
|
||||
|
||||
get middleware() {
|
||||
@ -186,6 +193,30 @@ export class Updux {
|
||||
this.#effects = [...this.#effects, [action, effect]];
|
||||
}
|
||||
|
||||
subscribeTo(store, subscription) {
|
||||
const localStore = augmentMiddlewareApi(
|
||||
{
|
||||
...store,
|
||||
subscribe: (subscriber) =>
|
||||
this.subscribeTo(store, () => subscriber),
|
||||
},
|
||||
this.actions,
|
||||
this.selectors
|
||||
);
|
||||
|
||||
const subscriber = subscription(localStore);
|
||||
|
||||
let previous;
|
||||
|
||||
const unsub = store.subscribe(() => {
|
||||
const state = store.getState();
|
||||
if (state === previous) return;
|
||||
let p = previous;
|
||||
previous = state;
|
||||
subscriber(state, p, unsub);
|
||||
});
|
||||
}
|
||||
|
||||
createStore() {
|
||||
const store = reduxCreateStore(
|
||||
this.reducer,
|
||||
@ -211,7 +242,17 @@ export class Updux {
|
||||
};
|
||||
}
|
||||
|
||||
_subscribeToStore(store, this.subscriptions);
|
||||
this.#subscriptions.forEach((sub) => this.subscribeTo(store, sub));
|
||||
|
||||
for (const subdux in this.#subduxes) {
|
||||
const localStore = {
|
||||
...store,
|
||||
getState: () => store.getState()[subdux],
|
||||
};
|
||||
for (const subscription of this.#subduxes[subdux].subscriptions) {
|
||||
this.#subduxes[subdux].subscribeTo(localStore, subscription);
|
||||
}
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
@ -107,10 +107,7 @@ tap.test('subduxes subscriptions', async (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
tap.test( "subscription within subduxes", {only: true},async(t) => {
|
||||
|
||||
tap.test('subscription within subduxes', { todo: false }, async (t) => {
|
||||
let innerState = sinon.fake.returns(null);
|
||||
let outerState = sinon.fake.returns(null);
|
||||
|
||||
@ -118,26 +115,33 @@ tap.test( "subscription within subduxes", {only: true},async(t) => {
|
||||
initial: 1,
|
||||
actions: { inc: null },
|
||||
mutations: {
|
||||
inc: () => state => state + 1,
|
||||
inc: () => (state) => state + 1,
|
||||
},
|
||||
subscriptions: [
|
||||
store => (state, previous, unsub) => {
|
||||
if(!previous) return;
|
||||
store.subscribe( innerState );
|
||||
(store) => (state, previous, unsub) => {
|
||||
console.log(state, previous);
|
||||
if (!previous) return;
|
||||
store.subscribe(innerState);
|
||||
unsub();
|
||||
}
|
||||
},
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
const dux = new Updux({
|
||||
initial: { x: 0 },
|
||||
subduxes: { inner },
|
||||
actions: {
|
||||
incOuter: null,
|
||||
},
|
||||
mutations: {
|
||||
incOuter: () => (state) => ({ ...state, x: state.x + 1 }),
|
||||
},
|
||||
subscriptions: [
|
||||
store => (state, previous, unsub) => {
|
||||
console.log(state,previous);
|
||||
if(!previous) return;
|
||||
store.subscribe( outerState );
|
||||
(store) => (state, previous, unsub) => {
|
||||
if (!previous) return;
|
||||
store.subscribe(outerState);
|
||||
unsub();
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -146,17 +150,39 @@ tap.test( "subscription within subduxes", {only: true},async(t) => {
|
||||
store.dispatch({ type: 'noop' });
|
||||
store.dispatch({ type: 'noop' });
|
||||
|
||||
t.notOk( innerState.called );
|
||||
t.notOk( outerState.called );
|
||||
t.notOk(innerState.called);
|
||||
t.notOk(outerState.called);
|
||||
|
||||
store.dispatch.inc();
|
||||
// still not called, but waiting, now
|
||||
t.notOk( innerState.called );
|
||||
t.notOk( outerState.called );
|
||||
|
||||
// not called yet
|
||||
t.notOk(innerState.called);
|
||||
t.notOk(outerState.called);
|
||||
|
||||
store.dispatch.inc();
|
||||
console.log(outerState.firstCall.args);
|
||||
// console.log(outerState.firstCall)
|
||||
t.ok(outerState.calledOnce);
|
||||
t.same(outerState.firstCall.args[0], { inner: 3, x: 0 });
|
||||
|
||||
t.ok(innerState.calledOnce);
|
||||
t.same(innerState.firstCall.args[0], 3);
|
||||
|
||||
} );
|
||||
innerState.resetHistory();
|
||||
outerState.resetHistory();
|
||||
|
||||
store.dispatch.inc();
|
||||
|
||||
t.ok(outerState.calledOnce);
|
||||
t.same(outerState.firstCall.args[0], { inner: 4, x: 0 });
|
||||
|
||||
t.ok(innerState.calledOnce);
|
||||
t.same(innerState.firstCall.args[0], 4);
|
||||
|
||||
await t.test('state of subdux doesnt change', async (t) => {
|
||||
innerState.resetHistory();
|
||||
outerState.resetHistory();
|
||||
store.dispatch.incOuter();
|
||||
|
||||
t.ok(outerState.calledOnce);
|
||||
t.notOk(innerState.called);
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user