Skip to content

sashion/mini-rx-store

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

MiniRx - RxJS Redux Store - Logo

NPM semantic-release MIT License Tests All Contributors Downloads styled with prettier

MiniRx Store 4

MiniRx Store 4 has been released!

What's new?

  • Refactor to Nx
  • Even more lightweight
  • tapResponse operator (handle API response in FeatureStore.effect)
  • mapResponse operator (handle API response in Redux Effects)
  • Allow many Feature Store instances with the same feature key using the multi: true config
  • FeatureStore.effect: the returned function accepts also an Observable as argument
  • createEffect can be used to create non-dispatching effects (using the dispatch: false config)
  • Many more internal improvements

Read more in the CHANGELOG about the changes and the very few BREAKING CHANGES.

Angular Integration (mini-rx-store-ng)

  • Full Ivy support in Angular
  • BREAKING CHANGE: createEffect must be used for creating effects which are registered via the EffectsModule

Read more in the CHANGELOG of the Angular Integration.

Installation

npm i mini-rx-store@4

Install the Angular Integration if you are using Angular:

npm i mini-rx-store-ng@3

The Angular Integration requires now Angular@12.

MiniRx Store

MiniRx Store provides Reactive State Management for JavaScript and TypeScript applications. It is a global, application-wide solution to manage state and is powered by RxJS. MiniRx will help you to manage state at large scale (with the Redux pattern), but it also offers a simple form of state management: Feature Stores.

What's Included

  • RxJS powered global state management
  • State and actions are exposed as RxJS Observables
  • Store (Redux API):
    • Actions
    • Reducers
    • Meta Reducers
    • Memoized Selectors
    • Effects
    • mapResponse operator: handle the side effect response in Effects
    • Support for ts-action: Create and consume actions with as little boilerplate as possible
  • Feature Store: Manage feature state directly with a minimum of boilerplate:
    • setState() update the feature state
    • select() select state from the feature state object as RxJS Observable
    • effect() run side effects like API calls and update feature state
    • undo() easily undo setState actions (requires UndoExtension)
    • destroy() remove the feature state
    • tapResponse operator: handle the side effect response in Feature Store effect
  • Extensions:
    • Redux DevTools Extension: Inspect global state with the Redux DevTools
    • Immutable Extension: Enforce state immutability
    • Undo Extension: Undo dispatched actions
    • Logger Extension: console.log the current action and updated state
  • Framework-agnostic: MiniRx works with any front-end project built with JavaScript or TypeScript (Angular, Svelte, React, Vue, or anything else)
  • TypeScript support: The MiniRx API comes with TypeScript type definitions
  • Angular Integration: Use MiniRx Store the Angular way:
    • Configure the Store with StoreModule.forRoot()
    • Add feature state with StoreModule.forFeature()
    • Inject Store and Actions

Key Concepts

  • The store is a single object which holds the global application state. It is the "single source of truth"
  • State and actions are exposed as RxJS Observables
  • State has a flat hierarchy and is divided into "feature states" (also called "slices" in Redux world)
  • For each "feature state" we can decide to use the Redux API with actions and reducers or the simplified Feature Store API
  • State is read-only (immutable) and can only be changed by dispatching actions (Redux API) or by using setState (Feature Store API)

Installation

Install from the NPM repository using npm:

npm install mini-rx-store

Install the RxJS peer dependency:

npm install rxjs

Basic Tutorial

Let's dive into some code to see MiniRx in action. You can play with the tutorial code on StackBlitz.

Store (Redux API)

MiniRx supports the classic Redux API with registering reducers and dispatching actions. Observable state can be selected with memoized selectors.

import {
  Action,
  Store,
  configureStore,
  createFeatureSelector,
  createSelector
} from 'mini-rx-store';
import { Observable } from 'rxjs';

// 1.) State interface
interface CounterState {
  count: number;
}

// 2.) Initial state
const counterInitialState: CounterState = {
  count: 1
};

// 3.) Reducer
function counterReducer(
  state: CounterState = counterInitialState,
  action: Action
): CounterState {
  switch (action.type) {
    case 'inc':
      return {
        ...state,
        count: state.count + 1
      };
    default:
      return state;
  }
}

// 4.) Get hold of the store instance and register root reducers
const store: Store = configureStore({
  reducers: {
    counter: counterReducer
  }
});

// 5.) Create memoized selectors
const getCounterFeatureState = createFeatureSelector<CounterState>('counter');
const getCount = createSelector(
  getCounterFeatureState,
  state => state.count
);

// 6.) Select state as RxJS Observable
const count$: Observable<number> = store.select(getCount);
count$.subscribe(count => console.log('count:', count));
// OUTPUT: count: 1

// 7.) Dispatch an action
store.dispatch({ type: 'inc' });
// OUTPUT: count: 2

Feature Store API

With MiniRx Feature Stores we can manage feature state directly with a minimum of boilerplate.

import { FeatureStore } from 'mini-rx-store';
import { Observable } from 'rxjs';

// State interface
interface CounterState {
  count: number;
}

// Initial state
const counterInitialState: CounterState = {
  count: 11
};

// Extend FeatureStore and pass the State interface
export class CounterFeatureStore extends FeatureStore<CounterState> {
  // Select state as RxJS Observable
  count$: Observable<number> = this.select(state => state.count);

  constructor() {
    // Call super with the feature key and the initial state
    super('counterFs', counterInitialState);
  }

  // Update state with `setState`
  inc() {
    this.setState(state => ({ count: state.count + 1 }));
  }
}

Use the "counterFs" Feature Store like this:

import { CounterFeatureStore } from "./counter-feature-store";

const counterFs = new CounterFeatureStore();
counterFs.count$.subscribe(count => console.log('count:', count));
// OUTPUT: count: 11

counterFs.inc();
// OUTPUT: count: 12

ℹ️ The state of a Feature Store becomes part of the global state

Every new Feature Store will show up in the global state with the corresponding feature key (e.g. 'counterFs').

store.select(state => state).subscribe(console.log);
//OUTPUT: {"counter":{"count":2},"counterFs":{"count":12}}

See the basic tutorial on Stackblitz: MiniRx Store - Basic Tutorial

Demos and examples:

Demos:

These popular Angular demo applications show the power of MiniRx:

More about MiniRx:

Blog Posts:

References

These projects, articles and courses helped and inspired us to create MiniRx:

License

MIT

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Pieter Van Poyer

πŸ’»

Florian Spier

πŸ’» πŸ€”

Carsten

🎨

Maximo Cudich-Sieburger

πŸ’»

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Lightweight Redux Store based on RxJS

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 87.7%
  • HTML 10.1%
  • JavaScript 1.9%
  • Other 0.3%