rxcomp-store
v1.0.0-beta.18
Published
Reactive StoreModule for RxComp component library
Downloads
6
Maintainers
Readme
💎 RxComp StoreModule
RxComp Store is a small Javascript module for RxComp, developed with Immer and RxJs as a simple alternative to Redux.
The store can however be used with any framework or VanillaJS.
lib & dependancy | size :--------------------|:----------------------------------------------------------------------------------------------| rxcomp-store.min.js | rxcomp-store.min.js | rxcomp.min.js | rxcomp.min.js | rxjs.min.js | rxjs.min.js | immer.min.js | immer.min.js |
Installation and Usage
ES6 via npm
This library depend on RxComp Immer and RxJs
install via npm or include via script
npm install rxjs immer rxcomp rxcomp-store --save
CDN
For CDN, you can use unpkg
<script src="https://unpkg.com/@reactivex/[email protected]/dist/global/rxjs.umd.min.js" crossorigin="anonymous" SameSite="none Secure"></script>
<script src="https://unpkg.com/[email protected]/dist/immer.umd.production.min.js" crossorigin="anonymous" SameSite="none Secure"></script>
<script src="https://unpkg.com/[email protected]/dist/umd/rxcomp.min.js" crossorigin="anonymous" SameSite="none Secure"></script>
<script src="https://unpkg.com/[email protected]/dist/umd/rxcomp-store.min.js" crossorigin="anonymous" SameSite="none Secure"></script>
The global namespace for RxComp is rxcomp
import { CoreModule, Module } from 'rxcomp';
The global namespace for RxComp StoreModule is rxcomp.store
import { StoreModule } from 'rxcomp-store';
The store
With the useStore
factory we create the immutable store with a default value.
The store will be consumed by a singleton service, and honoring the single-responsibility principle only a specific portion of the app data will be stored.
import { useStore } from 'rxcomp-store';
const { state$ } = useStore({ todolist: [] });
Subscribing to the state$
observable you always get the last immutable copy of the state
draft.
state$.subscribe(state => this.todolist = state.todolist);
Reducing the store state
The reducer
operator accept a reducer callback with the observable$
payload and a mutable draft of the state
as parameter.
When reducer returns, an immutable copy of the state will be pushed to the state$
observable through Immer.
const { reducer } = useStore({ todolist: [] });
observable$.pipe(
reducer((todolist, state) => state.todolist = todolist)
);
Retry state
The retryState
operator will retry N times before throwing the error.
const { retryState } = useStore({ todolist: [] });
observable$.pipe(
retryState(3),
);
Catching errors into the state
The catchState
operator is used to catch the error and store it in the immutable state.
const { catchState } = useStore({ todolist: [] });
observable$.pipe(
catchState(console.log),
);
You can then observe the state for errors.
state$.subscribe(state => this.error = state.error);
Canceling
The cancel
method will interrupt all the currently running streams in the store.
This method will not abort the fetch requests.
const { cancel } = useStore({ todolist: [] });
// stop currently running streams
cancel();
Setting the busy state
The busy$
observable will store the busy flag in the immutable state and lock future calls until the observable completes.
const { busy$ } = useStore({ todolist: [] });
busy$().pipe(
switchMap(() => observable$),
);
You can then observe the busy state.
state$.subscribe(state => this.busy = state.busy);
Loading state from Web Api Storage or Cookie
While reloading the page, you may want to reload the previous state of the app.
First we have to initialize the store with a different StoreType
(the default is StoreType.Memory
) and give it a unique store name.
import { StoreType, useStore } from 'rxcomp-store';
const { cached$ } = useStore({ todolist: [] },
StoreType.Session, 'todolist'
);
With the cached$
observable we can retrieve the last saved state from sessionStorage
or localStorage
or cookie
.
cached$((state) => state.todolist)
All together
- busy$ mark state as busy
- cached$ load data from cache
- reducer reduce the state to the new state
- retryState repeat the request N times then throw error.
- catchState catch the error and reduce the state to the errored state.
import { StoreType, useStore } from 'rxcomp-store';
const { busy$, cached$, reducer, retryState, catchState } = useStore(
{ todolist: [] },
StoreType.Session, 'todolist'
);
busy$().pipe(
switchMap(() =>
merge(cached$((state) => state.todolist), fromApi$).pipe(
reducer((todolist, state) => state.todolist = todolist),
retryState(),
catchState(console.log),
)
)
);
Querying the store state
The select$
observable accept a reducer callback with an immutable copy of the state
as parameter and returns an immutable copy of a portion of the state
as observable.
const { select$ } = useStore({ todolist: [] });
const todolist$ = select$((state) => state.todolist);
Querying with select
The select
method works like the select$
observable but doesn't return an observable.
const { select } = useStore({ todolist: [] });
const todolist = select((state) => state.todolist);
Other methods
Setting the store state
The next
method accept a reducer callback with a mutable draft of the state
as parameter.
When reducer returns, an immutable copy of the state will be pushed to the state$
observable through Immer.
It works like the reduce
operator but doesn't return an observable.
const { next } = useStore({ todolist: [] });
next((state) => state.todolist = todolist))
Setting the store error
The nextError
method will store the error
parameter in the immutable state.
It works like the catchState
operator but is intended to use in conjunction of classic catchError
operator.
const { nextError } = useStore({ todolist: [] });
catchError(error => nextError(error))
Bootstrapping Module
import { Browser, CoreModule, Module } from 'rxcomp';
import { StoreModule } from 'rxcomp-store';
import AppComponent from './app.component';
export default class AppModule extends Module {}
AppModule.meta = {
imports: [
CoreModule,
StoreModule
],
declarations: [],
bootstrap: AppComponent,
};
Browser.bootstrap(AppModule);
Browser Compatibility
RxComp supports all browsers that are ES5-compliant (IE8 and below are not supported).
Contributing
Pull requests are welcome and please submit bugs 🐞
Install packages
npm install
Build, Serve & Watch
gulp
Build Dist
gulp build --target dist
Thank you for taking the time to provide feedback and review. This feedback is appreciated and very helpful 🌈
If you find it helpful, feel free to contribute in keeping this library up to date via PayPal
Contact
- Luca Zampetti [email protected]
- Follow @actarian on Twitter
Release Notes
Changelog here.