reactive-state

by Dynalon

Dynalon /reactive-state

Redux-clone build with strict typing and RxJS down to its core. Wrist-friendly, no boilerplate or en...

128 Stars 6 Forks Last release: Not found MIT License 376 Commits 69 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Build Status npm version code coverage

Reactive State

A typed, wrist-friendly state container aimed as an alternative to Redux when using RxJS. Written with RxJS in TypeScript but perfectly usable from plain JavaScript. Originally inspired by the blog posting from Michael Zalecki but heavily modified and extended since.

Features

  • type-safe actions: no boilerplate code, no mandatory string constants, and not a single switch statement
  • Actions are just Observables, so are Subjects. Just call
    .next()
    to dispatch an action.
  • dynamically add and remove reducers during runtime
  • no need for async middlewares such as redux-thunk/redux-saga; actions are Observables and can be composed and transformed async using RxJS operators
  • no need for selector libraries like MobX or Reselect, RxJS already ships it
  • single, application-wide Store concept as in Redux. Possibility to create slices/substates for decoupling (easier reducer composition and state separation by module)
  • Strictly typed to find errors during compile time
  • Heavily unit tested, 100+ tests for ~250 lines of code
  • React bridge (like
    react-redux
    ) included, though using React is not mandatory
  • Support for React-Devtool Extension

Installation

npm install reactive-state

Documentation

Additionally, there is a small example.ts file and see also see the included unit tests as well.

Example Usage

import { Store } from "reactive-state";
import { Subject } from "rxjs";
import { take } from "rxjs/operators";

// The state for our example app interface AppState { counter: number; }

const initialState: AppState = { counter: 0 }

const store = Store.create(initialState);

// The .watch() function returns an Observable that emits the selected state change, so we can subscribe to it store.watch().subscribe(newState => console.log("STATE:", JSON.stringify(newState)));

// the watch() observable always caches the last emitted state, so we will immediately print our inital state: // [CONSOLE.LOG]: STATE: {"counter":0}

// use a RxJS Subjects as an action const incrementAction = new Subject();

// A reducer is a function that takes a state and an optional payload, and returns a new state function incrementReducer(state, payload) { return { ...state, counter: state.counter + payload }; };

store.addReducer(incrementAction, incrementReducer);

// lets dispatch some actions

incrementAction.next(1); // [CONSOLE.LOG]: STATE: {"counter":1} incrementAction.next(1); // [CONSOLE.LOG]: STATE: {"counter":2}

// async actions? No problem, no need for a "middleware", just use RxJS interval(1000).pipe(take(3)).subscribe(() => incrementAction.next(1)); // // [CONSOLE.LOG]: STATE: {"counter":3} // // [CONSOLE.LOG]: STATE: {"counter":4} // // [CONSOLE.LOG]: STATE: {"counter":5}

License

MIT.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.