Storx(2)
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 whendispatch
is called. Stores the state object and - depending on an event type definition (effectful or effectless) - may also perform updates. -
Events (effectful | effectless)
- tuples ofSubject
and nullable transformation function, discriminated withkind
property. Created via 2-ary constructor function that allows strict, granular control over the transformation function definition. -
Effects
- givenStore
andEvent
(s) referencesEffect
will 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 RxJSselect
operator. Selectors are memoized, values are compared using deep-is algorithm.
Installation
npm i @tanfonto/storx2
or
yarn add @tanfonto/storx2
API
-
Store
creation
import { Store, EventStream, Effect, select } from '@tanfonto/storx2';
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 }
})
-
Effects
creation
const makeEffect = Effect(store);
makeEffect(eventStream, (state, patch) => {
console.log(state, patch);
// { prop: 50 } 42
});
store.dispatch(eventStream, 42);
- Chained
Effects
creation
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 (
select
operator)
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