Miss any of our Open RFC calls?Watch the recordings here! »

This package has been deprecated

Author message:

use @recubed/storx instead

@tanfonto/storx

1.4.0 • Public • Published

Deprecated, use Storx instead

BuildStatus Coverage Status CodeFactor dependenciesStatus devDependencies Status MITlicense

| storx |

Centralised state management powered by RxJS & TypeScript;

Features

  • small and concise;

  • dependency-free (minus RxJS, obviously);

  • dead simple api (see 'usage' below and tests);

  • RxJS compatible, meaning you can plug it into your streams right away;

  • functional, statically typed codebase;

Installation

npm i @tanfonto/storx

or

yarn add @tanfonto/storx

Usage examples

basic

import { Store } from '@tanfonto/storx';
 
type No = { value: number };
 
const store = Store(
  // initial state
  { value: 1 },
  // a key / value map of action reducers
  {
    inc: ({ value: v1 }: No, { value: v2 }: No) => ({ value: v1 + v2 }),
    dec: ({ value: v1 }: No, { value: v2 }: No) => ({ value: v1 - v2 })
  }
);
 
const { state, dispatch } = store;
 
// subscribe to state changes
state.subscribe(console.log);
 
// dispatch 'inc' action
dispatch('inc', { value: 4 });
// dispatch 'dec' action
dispatch('dec', { value: 2 });
 
// dispatch 'anonymous' action
dispatch((x: No) => ({ value: x.value + 3 }));
 
// dispatch parametrised 'unbound' action from closure
function closure(val: number) {
  dispatch((x: No) => ({ value: x.value + val }));
}
 
closure(4);
 
// output:
// { value: 5 }
// { value: 3 }
// { value: 6 }
// { value: 10 }

with pre-update side effects

// since 1.1 - declare a (pre) state update side effect
const storeWithEffects = Store(
  { value: 1 },
  {
    inc: ({ value: v1 }, { value: v2 }) => ({ value: v1 + v2 })
  },
  // Here's the place:
  console.log
);
 
const { state, dispatch } = store;
 
dispatch('inc', { value: 42 });
state.subscribe(console.log);
state.subscribe(console.log);
 
// output (note that side effect was only triggered once despite two 'subscribe' registrations):
// [ 'inc', { value: 42 } ]
// { value: 43 }
// { value: 43 }

Core concepts

actions

In contrast to popular state management libraries, Storx actions represent actual transformations rather then intents or descriptors. This decision has obvious flexibility / granularity implications but also helps reducing boilerplate and overall complexity. It's a simplicity-oriented tradeoff but the main driver for this design is to serve as a lightweight scan operator wrapper and RxJS pipeline rather than custom state management implementation.

state calculation

Because of how Storx defines actions it does not need an explicit reducer layer. Whatever gets dispatched to the store will implicitly transform the state and emit the result to subscribers.

listening to state changes

Given Store instance is an RxJS observable the only functional limitation to its streaming capabilities is RxJS api pipeline, meaning more or less - unlimited power, some ideas follow:

Building blocks and composition

of s: Functor s -> SubjectLike ActionRecord

Constructor. creates a (private) instance of ReplaySubject and returns it converted to Observable extended with custom next function that may take one of two forms:

- Functor s -> void
- (key, payload) p -> void

runEffects s: [ (ActionRecord s -> void) ] -> void

fires a list of unary functions with a tuple of (key, payload) representing action name and patch data as their first and only argument.

findAction s: Config s -> ActionRecord s -> Functor s

given configuration object, keys of which represent actions names and values describing binary functions of (state, patch) and argument being a (1) tuple of (key, payload) or (2) unary function it will detect which of these 2 forms was used and either shorten a binary functor to curried unary version (by closing on patch data) or pass the free (unary) one for further processing.

calculateState s: s -> Observable Functor s -> Observable s

runs the emitted functor against current state and emits the result.

The exemplary Store implementation consists of these 4 composed in above order, wrapped in appropriate RxJS operators. Exposing isolated pipes brings an opportunity of reimplementation to ones flavour, i.e. by injecting additional pipes or cutting some of the logic.

Please note that 'functor' is used to describe the 'map' function of CT functor rather than container itself as it is always used in a context of observable mapping.

Incoming

  • History api / time travelling

  • Snapshots

Install

npm i @tanfonto/storx

DownloadsWeekly Downloads

81

Version

1.4.0

License

MIT

Unpacked Size

28.3 kB

Total Files

63

Last publish

Collaborators

  • avatar