RxJS powered state management for Angular applications, inspired by Redux
@ngrx/store is a controlled state container designed to help write performant, consistent applications on top of Angular. Core tenets:
- State is a single, immutable data structure.
- Actions describe state changes.
- Pure functions called reducers take the previous state and the next action to compute the new state.
- State accessed with the
Store
, an observable of state and an observer of actions.
These core principles enable building components that can use the OnPush
change detection strategy
giving you intelligent, performant change detection
throughout your application.
Install @ngrx/store from npm:
npm install @ngrx/store --save
OR yarn add @ngrx/store
npm install github:ngrx/store-builds
OR yarn add github:ngrx/store-builds
Create a reducer function for each data type you have in your application. The combination of these reducers will make up your application state:
// counter.ts
import { Action } from '@ngrx/store';
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';
export function counterReducer(state: number = 0, action: Action) {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
case RESET:
return 0;
default:
return state;
}
}
To register the state container within your application, import the reducers and use the StoreModule.forRoot
function in the imports
array of the @NgModule
decorator for your AppModule
.
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter';
@NgModule({
imports: [BrowserModule, StoreModule.forRoot({ count: counterReducer })],
})
export class AppModule {}
You can then inject the Store
service into your components and services. Use select
operator to select slice(s) of state:
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';
import { INCREMENT, DECREMENT, RESET } from './counter';
interface AppState {
count: number;
}
@Component({
selector: 'my-app',
template: `
<button (click)="increment()">Increment</button>
<div>Current Count: {{ count$ | async }}</div>
<button (click)="decrement()">Decrement</button>
<button (click)="reset()">Reset Counter</button>
`,
})
export class MyAppComponent {
count$: Observable<number>;
constructor(private store: Store<AppState>) {
this.count$ = store.pipe(select('count'));
}
increment() {
this.store.dispatch({ type: INCREMENT });
}
decrement() {
this.store.dispatch({ type: DECREMENT });
}
reset() {
this.store.dispatch({ type: RESET });
}
}