@tanfonto/storx2 v0.1.0
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 when- dispatchis called. Stores the state object and - depending on an event type definition (effectful or effectless) - may also perform updates.
- Events (effectful | effectless)- tuples of- Subjectand nullable transformation function, discriminated with- kindproperty. Created via 2-ary constructor function that allows strict, granular control over the transformation function definition.
- Effects- given- Storeand- Event(s) references- Effectwill 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 RxJS- selectoperator. Selectors are memoized, values are compared using deep-is algorithm.
Installation
npm i @tanfonto/storx2or
yarn add @tanfonto/storx2API
- Storecreation
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 }
}) - 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