MiniRx Store 5 (alpha)
MiniRx Store 5 (alpha) has been released (2023-01-23)!
What's new?
- Component Store:
- Manage state independently of the global state object (which is used by Store and Feature Store)
- Component Store and Feature Store share the same API (
setState
,select
,effect
...) - Component Store is perfect for managing smaller and local state (most times that is Component state)
- You can use most of the MiniRx extensions: Logger Extension, Undo Extension and Immutable Extension
- Component Store extensions can be configured globally or individually for each store
- Tree-shakable: even more lightweight!
- Lazy state initialisation with
setInitialState
setState
accepts also an Observable: use an Observable to update state
Read more in the CHANGELOG about the changes and the very few BREAKING CHANGES.
Angular Integration (mini-rx-store-ng)
ComponentStoreModule
: Configure ComponentStore extensions globally with theforRoot
static method- BREAKING CHANGE:
StoreDevtoolsModule
has been removed. You can use now the normalReduxDevtoolsExtension
from mini-rx-store withStoreModule.forRoot
.
Read more in the CHANGELOG of the Angular Integration.
Installation
npm i mini-rx-store@5@alpha
Install the Angular Integration if you are using Angular:
npm i mini-rx-store-ng@4@alpha
The Angular Integration requires now Angular@12.
Final todos until the major release
- Update documentation
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.
-
🤓 Learn about MiniRx on the docs site -
🚀 See MiniRx in action:
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 stateselect()
select state from the feature state object as RxJS Observableeffect()
run side effects like API calls and update feature stateundo()
easily undo setState actions (requires UndoExtension)destroy()
remove the feature statetapResponse
operator: handle the side effect response in Feature Storeeffect
- 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
andActions
- Configure the Store with
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
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:
- Angular MiniRx Demo on GitHub
- See it live here
- Svelte MiniRx Demo on GitHub
- See it live here
These popular Angular demo applications show the power of MiniRx:
- Angular Tetris with MiniRx on GitHub
- Angular Jira Clone using MiniRx on GitHub
- Angular Spotify using MiniRx on GitHub
More about MiniRx:
Blog Posts:
- Introducing MiniRx - Scalable reactive state management
- MiniRx Feature Store vs. NgRx Component Store vs. Akita
Community
References
These projects, articles and courses helped and inspired us to create MiniRx:
- NgRx
- Akita
- Observable Store
- RxJS Observable Store
- Juliette Store
- Basic State Management with an Observable Service
- Redux From Scratch With Angular and RxJS
- How I wrote NgRx Store in 63 lines of code
- NGRX VS. NGXS VS. AKITA VS. RXJS: FIGHT!
- Pluralsight: Angular NgRx: Getting Started
- Pluralsight: RxJS in Angular: Reactive Development
- Pluralsight: RxJS: Getting Started
License
MIT
✨
Contributors Thanks goes to these wonderful people (emoji key):
Pieter Van Poyer |
Florian Spier |
Carsten |
Maximo Cudich-Sieburger |
sashion |
BrainCrumbz |
This project follows the all-contributors specification. Contributions of any kind welcome!