@lacolaco/ngx-store
v5.0.0
Published
Minimal state management for Angular
Downloads
12
Readme
@lacolaco/ngx-store
Minimal state management library for Angular based on RxJS.
https://yarn.pm/@lacolaco/ngx-store
Install
$ yarn add @lacolaco/ngx-store
How to Use
Create a store
A "store" is an Angular service which hold its state.
- Define a class which extends
Store<T>
. - Pass the initial state to
super({ initialState })
; - Decorate the class with
@Injectable()
as well as other usual Angular services.
import { Injectable } from '@angular/core';
import { Store } from '@lacolaco/ngx-store';
export interface State {
count: number;
}
export const initialState: State = {
count: 0,
};
// Also you can use your NgModule's `providers` array to provide this service.
@Injectable({ providedIn: 'root' })
export class CounterStore extends Store<State> {
constructor() {
super({ initialState });
}
}
Use the store
- Inject your store.
- Select specific value from the store with
selectValue
.
@Component({
selector: 'app-root',
template: `
<p>Counter: {{ count$ | async }}</p>
`,
})
export class AppComponent implements OnInit {
constructor(private counterStore: CounterStore) {}
}
selectValue((state: T) => U): Observable<U>
: Observe selected state change
selectValue
method is for mapping and memoize. Internally it uses RxJS's map
and distinctUntilChanged
operators.
@Component({
selector: 'app-root',
template: `
<p>Counter: {{ count$ | async }}</p>
`,
})
export class AppComponent implements OnInit {
count$: Observable<number>;
constructor(private counterStore: CounterStore) {
this.count$ = this.counterStore.selectValue(state => state.count);
}
}
valueChanges: Observable<T>
: Observe whole state changes
valueChanges
is a raw observable of the store.
@Component({
selector: 'app-root',
template: `
<p>Counter: {{ count$ | async }}</p>
`,
})
export class AppComponent implements OnInit {
count$: Observable<number>;
constructor(private counterStore: CounterStore) {
// same to `selectValue`
this.count$ = this.counterStore.valueChanges.pipe(
map(state => state.count),
distinctUntilChanged(),
);
}
}
updateValue((state: T) => T) void
: Update the store with new state
updateValue
takes a function which takes the current state and returns a new state.
@Component({
selector: 'app-root',
template: `
<p>Counter: {{ count$ | async }}</p>
`,
})
export class AppComponent implements OnInit {
count$: Observable<number>;
constructor(private counterStore: CounterStore) {
this.count$ = this.counterStore.selectValue(state => state.count);
}
ngOnInit() {
setInterval(() => {
this.counterStore.updateValue(state => ({ count: state.count }));
}, 1000);
}
}
Store Options
Listen onChange event
A store dispatchs an event when its state has been updated.
@Injectable({ providedIn: 'root' })
export class CounterStore extends Store<State> {
constructor() {
super({
initialState,
onUpdate: change => {
console.log(`Previous Value`, change.previousValue);
console.log(`Current Value`, change.currentValue);
console.log(`Action Name`, change.actionName);
},
});
}
}
actionName is the name of the function passed to updateValue
.
If you pass an anonymous function, change.actionName
is empty.
Named function is helpful for better logging or other purposes.
// Named function
const incrementOne = (state: CounterState) => ({
count: state.count + 1,
});
@Component({
selector: 'app-root',
template: `
<p>Counter: {{ count$ | async }}</p>
`,
})
export class AppComponent implements OnInit {
count$: Observable<number>;
constructor(private counterStore: CounterStore) {
this.count$ = this.counterStore.selectValue(state => state.count);
}
ngOnInit() {
setInterval(() => {
this.counterStore.updateValue(incrementOne);
}, 1000);
}
}
License
MIT
Author
Suguru Inatomi a.k.a. lacolaco
Patreon: https://www.patreon.com/lacolaco