@recubed/storx v1.0.0
Storx
RxJS-based state management. Borrows concepts from Redux, Effector and few others but targets minimalism and strong RxJS reliance rather than custom internals.
This is a revamped version of Storx. Differs from its predecessor in both implementation and dsl but persists the core ideas of simplicity and RxJS dependency.
Core artifacts
Store (known events[])- an object that relies on variable-size set of events (provided via constructor function) that it then triggers whendispatchis called. Stores the state object and - depending on an event type definition (effectful or effectless) - may also perform updates.Events (effectful | effectless)- tuples ofSubjectand nullable transformation function, discriminated withkindproperty. Created via 2-ary constructor function that allows strict, granular control over the transformation function definition.Effects- givenStoreandEvent(s) referencesEffectwill listen on event emissions and trigger side effects. If a tuple of event and transformation function is provided as a 2-nd argument effect will also run the transformation on source event payload and dispatch the result to the target event stream (second element of the aforementioned tuple).Selectors- Store projections created with custom RxJSselectoperator. Selectors are memoized, values are compared using deep-is algorithm.
Installation
npm i @recubed/storxor
yarn add @recubed/storxAPI
Storecreation
import { Store, EventStream, Effect, select } from '@recubed/storx';
import { skip } from 'rxjs/operators';
const eventStream = EventStream('some-event');
const otherEventStream = EventStream('other-event');
const store = Store({ prop: 42 }, eventStream, otherEventStream);- Dispatching events
store.allEvents.subscribe(ev => {
console.log(ev);
// { kind: 'some-event', status: 'successful' }
});
store.dispatch(eventStream);- Dispatching state updates
const effectfulEventStream = EventStream('update-prop', {
//where to find state slice to transform
select: state => state.prop,
//how to update the state
write: (state, patch) => ({ ...state, prop: patch }),
//how to transform previous value
xf: (value, patch) => value + patch
});
store.state.subscribe(state => {
console.log(state.prop);
// 50
});
store.dispatch(effectfulEventStream, 8);- Reading current state
console.log(store.valueOf());
// { prop: 50 }- Reading current state and last update-causing event
import { withReason } from '@tanfonto/storx';
withReason(store).subscribe([ state, event ] => {
console.log(state, event);
// { prop: 50 } { kind: 'update-prop', status: 'successful', patch: 8 }
}) Effectscreation
const makeEffect = Effect(store);
makeEffect(eventStream, (state, patch) => {
console.log(state, patch);
// { prop: 50 } 42
});
store.dispatch(eventStream, 42);- Chained
Effectscreation
const makeEffect = Effect(store);
makeEffect(eventStream, [otherEventStream, (_state, patch) => patch]);
store.allEvents.pipe(skip(1)).subscribe(ev => {
console.log(ev);
// { kind: 'other-event', status: 'successful', patch: 42 }
});
store.dispatch(eventStream, 42);- Selectors (
selectoperator)
store.state.pipe(select(x => x.prop))
.subscribe(x => {
console.log(x)
//42, 9001 [selectors are memoized therefore second dispatch will not emit]
});
store.dispatch(eventStream, 42);
store.dispatch(eventStream, 42);
store.dispatch(eventStream, 9001);
});
store.dispatch(eventStream, 42);Examples
- Using with
Angular: check this stackblitz - Using with
React: check this codesandbox
License
MIT
5 years ago