RxJS powered state management inspired by Redux for Angular 2 applications
@ngrx/store is a controlled state container designed to help write performant, consistent applications on top of Angular 2. Essentially:
- State is implemented as an immutable data structure
- Changes to state are described using actions
- Pure functions called reducers take the previous state and the next action to compute the new state
- State is contained inside of 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/core and @ngrx/store from npm:
npm install @ngrx/core @ngrx/store --saveOptional packages:
- @ngrx/store-devtools instruments your store letting you use a powerful time-travelling debugger.
- @ngrx/store-router contains the state of @angular/router in your store
- @ngrx/effects isolates side effects from your UI by expressing side effects as sources of actions
- Official @ngrx/example-app Officially maintained example application showcasing best practices for many @ngrx projects, including @ngrx/store and @ngrx/effects
- angular-webpack2-starter Complete Webpack 2 starter with support for @ngrx built-in. Includes support for the Ahead-of-Time (AOT) compiler, hot module reloading (HMR), devtools, and server-side rendering.
- Reactive Angular 2 with ngrx (video)
- Comprehensive Introduction to @ngrx/store
- @ngrx/store in 10 minutes (video)
- Build Redux Style Applications with Angular2, RxJS, and ngrx/store (video)
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 { ActionReducer, Action } from '@ngrx/store';
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';
export const counterReducer: ActionReducer<number> = (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;
}
}In your app's main module, import those reducers and use the StoreModule.provideStore(reducers)
function to provide them to Angular's injector:
import { NgModule } from '@angular/core'
import { Store, StoreModule } from '@ngrx/store';
import { counterReducer } from './counter';
@NgModule({
imports: [
BrowserModule,
StoreModule.provideStore({ counter: counterReducer })
]
})
export class MyAppModule {}You can then inject the Store service into your components and services. Use store.select to
select slice(s) of state:
import { Store } from '@ngrx/store';
import { INCREMENT, DECREMENT, RESET } from './counter';
interface AppState {
counter: number;
}
@Component({
selector: 'my-app',
template: `
<button (click)="increment()">Increment</button>
<div>Current Count: {{ counter | async }}</div>
<button (click)="decrement()">Decrement</button>
`
})
class MyApp {
counter: Observable<number>;
constructor(public store: Store<AppState>){
this.counter = store.select('counter');
}
increment(){
this.store.dispatch({ type: INCREMENT });
}
decrement(){
this.store.dispatch({ type: DECREMENT });
}
reset(){
this.store.dispatch({ type: RESET });
}
}Please read contributing guidelines here.