storeon-substore
Utility for creating feature sub store for Storeon.
It size is 420 B (minified and gzipped) and uses Size Limit to control size.
Overview
The goal of this library is provide the easy way to create feature sub store,
which allows to work on sub state (projection of parent state) within the storeon events handler and returns
sub state on get
method call.
During work with mid scale application you can notice that on multiple places
you have to make the projection of state, eg:
export function featureCounterModule(store) {
store.on('@init', () => ({
feature: {
counter: 0
}
}));
store.on('featureIncrement', state => ({
feature: {
...state.feature,
counter: state.feature.counter + 1,
}
}));
store.on('featureDecrement', state => ({
feature: {
...state.feature,
counter: state.feature.counter - 1,
}
}));
store.on('featureSet', (state, count) => ({
feature: {
...state.feature,
counter: count
}
}));
}
To eliminate the duplication of state projection each time when you reduce your state
you can use feature sub store:
export function featureCounterModule(store) {
const featureStore = createSubstore(store, 'feature');
featureStore.on('@init', () => ({
counter: 0
}));
featureStore.on('featureIncrement', state => ({
counter: state.counter + 1,
}));
featureStore.on('featureDecrement', state => ({
counter: state.counter - 1,
}));
featureStore.on('featureSet', (state, count) => ({
counter: count
}));
}
Or even use sub store of sub store:
export function featureCounterModule(store) {
const featureStore = createSubstore(store, 'feature');
const featureCounterStore = createSubstore(featureStore, 'counter');
featureCounterStore.on('@init', () => 0);
featureCounterStore.on('featureIncrement', state => state + 1);
featureCounterStore.on('featureDecrement', state => state - 1);
featureCounterStore.on('featureDecrement', (state, count) => count);
}
Three important remarks:
- The state delivered to handler attached to sub store, can get the
undefined
value if the state of the feature is not yet set.
Install
npm i storeon-substore --save
Usage
import createStore from "storeon";
import { createSubstore } from "storeon-substore";
const store = createStore([]);
const featureStore = createSubstore(store, 'feature');
featureStore.on('toggleFeatureBooleanFlag', (state) => ({
flag: state ? !state.flag : true,
}));
featureStore.on('@changed', (state, diff) => {
});
featureStore.dispatch('toggleFeatureBooleanFlag');
featureStore.get();
Scoped events
This library allows also to scope the events. By default, substore is operates on same set of events
like parent store. But there is possibility to narrow scope of all dispatched events only to
substore handlers. This can be useful for storeon modules reuse. Look at the example:
import createStore from "storeon";
import { createSubstore } from "storeon-substore";
const counterModule = (store: StoreonStore<any>) => {
store.on('inc', state => ({
count: (state?.count || 0) + 1
}));
store.on('dec', state => ({
count: (state?.count || 0) + 1
}));
}
const store = createStoreon<any>([]);
const counterAStore = createSubstore(store, 'counterA', true);
counterModule(counterAStore);
const counterBStore = createSubstore(store, 'counterB', true);
counterModule(counterBStore);
counterAStore.dispatch('inc');
console.log(store.get())
counterBStore.dispatch('inc');
console.log(store.get())
Api
createSubstore
- is factory function which returns sub feature store. Params:
parent
the parent store, can be a result of createStore
or other sub store created by createSubstore
key
the sub state property key in parent statescopeEvents
(optional) boolean flag which will enable the events scoping,
so every event dispatched on the substore will be only scoped to this substore,
so only handlers attached to this substore will handle the event