Package Exports
- @gernsdorfer/ngrx-lite
- @gernsdorfer/ngrx-lite/package.json
- @gernsdorfer/ngrx-lite/testing
Readme
NgrxLite
A small angular State Mangement based on ngrx component-store, with some benefits 😎
Why we need this ?
The current @ngrx/component-store implementation works with its own isolated Store. Unfortunately, there is no connection to the global @ngrx/Store or the @ngrx/store-devtools.
This Library connects your @ngrx/component-store with the @ngrx/Store to share and debug the @ngrx/actions and store.
Benefits
- 🤝 same API like @ngrx/component-store with optional parameters
- ⏱ create fast and easy a dynamic redux store
- ⏳ optional integrated loading state for effects
- 🤯 debug your application State across different url's
- ⚒️ Support Redux Devtools for your light components-store (only if you use redux-devtools) for
- patchState
- setState
- createdLoadingEffects
- 💽 support session/locale Storage
- 🏘 You Decide where your Store lives: Root, Module or in the Component Scope
- 🔛 Shared your State Changes and Actions in the ngrx Store
- 📑 Store your Form Data to persists and debug
- ✍️ write your tests much easier
- 👩💻 checkout the Sample-App
- 📖 read the docs
UI-DEMO
Test-DEMO
Install
yarn: yarn add @ngrx/store @gernsdorfer/ngrx-lite
npm: npm install @ngrx/store @gernsdorfer/ngrx-lite
Usage
- Import
StoreModule
from ngrx to your root Module
@NgModule({
//...
imports: [StoreModule.forRoot({})]
//...
- Create Your Store
You have the same API as @ngrx/component-store
export interface MyState {
counter: number
}
@Component({
selector: 'my-component',
template: '<button (click)="load(\'test\')">',
})
class MyComponent implements OnDestroy {
// create a componentStore
private store = this.storeFactory.createComponentStore<MyState>({
storeName: 'BASIC_COUNTER',
defaultState: {counter: 0},
});
// read the state
public counterState$: Observable<MyState> = this.store.state$;
constructor(private storeFactory: StoreFactory) {
}
increment(counter: number) {
// patch your state
this.store.patchState({counter});
}
ngOnDestroy() {
// destory the store
this.store.ngOnDestroy();
}
}
That's it 🥳
Features
Devtool support
Install and import ngrx/store-devtools und have all Features from the devtools for your component store
Let's have a look into the the redux devtools whats going on, in the example above.
Store is init
After the store is init you can find the store in the @ngrx/devtools
Patch State
After patch State you see this in your redux devtool. It's possbile to define an custom Actionname for your patch/set State
Router Store
Import the RouterStoreModule
into your main application to debug your state across all visited URL's. This module
store's related URL to the current Store.
So it's possible to replay your state changes by revisiting the related url.
@NgModule({
//...
imports: [RouterStoreModule]
//...
Loading Store
Create LoaderStore to set a Loader State while an Effect is running. You have the same API as createComponentStore
with an extra methode loadingEffect
type State = LoadingStoreState<{ counter: number }, { message: string }>;
@Component({
selector: 'my-app-basic-app',
templateUrl: 'loading-effect.html',
})
export class LoadingEffectComponent implements OnDestroy {
// create your loading store
private store = this.storeFactory.createComponentLoadingStore<State['item'],
State['error']>({
storeName: 'LOADING_STORE',
});
// read the state
public counterState$: Observable<State> = this.store.state$;
// define your loadingEffect to change the state
public increment = this.store.loadingEffect(
'increment',
(counter: number = 0) => of(counter + 1)
);
constructor(private storeFactory: StoreFactory) {
}
ngOnDestroy() {
// destory the store
this.counterStore.ngOnDestroy();
}
}
What's going on ? Let's have a look into the the redux devtools
Store is init
After the store is init you can find the store in the @ngrx/devtools
Loader State isloading
changed
For a running Effect isLoading
is true and you can show a spinner in your UI.
Effect run successfully
After an Effect run Successfully the item
key is updated
Effect run unsuccessfully
After an Effect run unsuccessfully the error
key contains the error
Form Store
interface Product {
name: string;
}
@Component({
selector: 'my-app-basic-app',
templateUrl: 'persist-form.html',
})
export class PersistFormComponent implements OnDestroy {
productForm = new FormGroup({
name: new FormControl('', [Validators.required]),
lastName: new FormControl('', [Validators.required]),
});
private store = this.storeFactory.createFormComponentStore<Product>({
storeName: 'PRODUCT_FORM',
plugins: {
storage: 'sessionStoragePlugin',
},
formGroup: this.productForm
});
}
Session/Local Storage
Register Session/Locale-Storage Service
- Register Session/Locale-Storage in your Root-Module
@NgModule({
// ...
providers: [
{provide: SessionStoragePlugin, useValue: sessionStoragePlugin},
{provide: LocalStoragePlugin, useValue: localStoragePlugin}
]
// ...
})
- Create your new Store with a session Storage Sync Option
class MyLCass {
private store = this.storeFactory.createComponentStore<{ counter: number }>({
storeName: 'SESSION_COUNTER',
defaultState: {
counter: 0,
},
plugins: {
storage: 'sessionStoragePlugin',
},
});
}
Testing
Import storeTestingFactory
and write your test's. A minimal Example you can
find here
All Demo Unit Test's you can find
here:
TestBed.configureTestingModule({
//...
providers: [storeTestingFactory()],
//..
});