subscription within a subscription
This commit is contained in:
parent
c1c1edf588
commit
912ea85edc
73
src/Updux.js
73
src/Updux.js
@ -15,7 +15,19 @@ import {
|
|||||||
|
|
||||||
function _subscribeToStore(store, subscriptions) {
|
function _subscribeToStore(store, subscriptions) {
|
||||||
for (const sub of 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));
|
let unsub = store.subscribe(() => subscriber(store.getState(), unsub));
|
||||||
}
|
}
|
||||||
@ -31,7 +43,12 @@ const sliceSubscriber = (slice, subdux) => (subscription) => (store) => {
|
|||||||
subdux.selectors
|
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) => {
|
const memoizeSubscription = (subscription) => (store) => {
|
||||||
@ -71,9 +88,8 @@ export class Updux {
|
|||||||
for (const [type, actionArg] of Object.entries(config.actions)) {
|
for (const [type, actionArg] of Object.entries(config.actions)) {
|
||||||
if (typeof actionArg === 'function' && actionArg.type) {
|
if (typeof actionArg === 'function' && actionArg.type) {
|
||||||
this.#actions[type] = actionArg;
|
this.#actions[type] = actionArg;
|
||||||
}
|
} else {
|
||||||
else {
|
this.#actions[type] = action(type, actionArg);
|
||||||
this.#actions[type] = action(type,actionArg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,16 +119,7 @@ export class Updux {
|
|||||||
#memoMiddleware = moize(buildMiddleware);
|
#memoMiddleware = moize(buildMiddleware);
|
||||||
|
|
||||||
get subscriptions() {
|
get subscriptions() {
|
||||||
const subscriptions = [...this.#subscriptions].map((s) =>
|
return this.#subscriptions;
|
||||||
memoizeSubscription(s)
|
|
||||||
);
|
|
||||||
|
|
||||||
return [
|
|
||||||
...subscriptions,
|
|
||||||
...map(this.#subduxes, (v, k) =>
|
|
||||||
v.subscriptions.map(sliceSubscriber(k, v))
|
|
||||||
).flat(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get middleware() {
|
get middleware() {
|
||||||
@ -186,6 +193,30 @@ export class Updux {
|
|||||||
this.#effects = [...this.#effects, [action, effect]];
|
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() {
|
createStore() {
|
||||||
const store = reduxCreateStore(
|
const store = reduxCreateStore(
|
||||||
this.reducer,
|
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;
|
return store;
|
||||||
}
|
}
|
||||||
|
@ -107,10 +107,7 @@ tap.test('subduxes subscriptions', async (t) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tap.test('subscription within subduxes', { todo: false }, async (t) => {
|
||||||
|
|
||||||
tap.test( "subscription within subduxes", {only: true},async(t) => {
|
|
||||||
|
|
||||||
let innerState = sinon.fake.returns(null);
|
let innerState = sinon.fake.returns(null);
|
||||||
let outerState = 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,
|
initial: 1,
|
||||||
actions: { inc: null },
|
actions: { inc: null },
|
||||||
mutations: {
|
mutations: {
|
||||||
inc: () => state => state + 1,
|
inc: () => (state) => state + 1,
|
||||||
},
|
},
|
||||||
subscriptions: [
|
subscriptions: [
|
||||||
store => (state, previous, unsub) => {
|
(store) => (state, previous, unsub) => {
|
||||||
|
console.log(state, previous);
|
||||||
if (!previous) return;
|
if (!previous) return;
|
||||||
store.subscribe(innerState);
|
store.subscribe(innerState);
|
||||||
unsub();
|
unsub();
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
|
initial: { x: 0 },
|
||||||
subduxes: { inner },
|
subduxes: { inner },
|
||||||
|
actions: {
|
||||||
|
incOuter: null,
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
incOuter: () => (state) => ({ ...state, x: state.x + 1 }),
|
||||||
|
},
|
||||||
subscriptions: [
|
subscriptions: [
|
||||||
store => (state, previous, unsub) => {
|
(store) => (state, previous, unsub) => {
|
||||||
console.log(state,previous);
|
|
||||||
if (!previous) return;
|
if (!previous) return;
|
||||||
store.subscribe(outerState);
|
store.subscribe(outerState);
|
||||||
unsub();
|
unsub();
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -150,13 +154,35 @@ tap.test( "subscription within subduxes", {only: true},async(t) => {
|
|||||||
t.notOk(outerState.called);
|
t.notOk(outerState.called);
|
||||||
|
|
||||||
store.dispatch.inc();
|
store.dispatch.inc();
|
||||||
// still not called, but waiting, now
|
|
||||||
|
// not called yet
|
||||||
t.notOk(innerState.called);
|
t.notOk(innerState.called);
|
||||||
t.notOk(outerState.called);
|
t.notOk(outerState.called);
|
||||||
|
|
||||||
store.dispatch.inc();
|
store.dispatch.inc();
|
||||||
console.log(outerState.firstCall.args);
|
t.ok(outerState.calledOnce);
|
||||||
// console.log(outerState.firstCall)
|
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