RxJS 驱动的 Angular 应用状态管理工具,灵感来源于 Redux
。
@ngrx/store
是一个包含受控状态的容器,设计的目的在于帮助我们在 Angular
之上写出高性能、稳定的应用。核心原理:
State
是一个单一不可变的数据结构Actions
用于描述状态(state)的改变- 被称为
reducers
的纯函数,通过获取之前的状态(state),和下一次的 action,来计算出新的状态(state)。 - 状态可以通过
Store
来进行访问,Store
包含一个针对state
的可观察对象(observable)和一个对actions
的观察者(observer)
通过这些核心原理,你可以在构建组件时使用 OnPush
变化检测(change detection)策略,让智能且高效的变化检测(intelligent,performant change detection)贯穿在你的应用中。
通过 npm
安装 @ngrx/store
npm install @ngrx/store --save
或者 yarn add @ngrx/store
npm install github:ngrx/store-builds
或者 yarn add github:ngrx/store-builds
为你应用中的每种数据类型创建一个 reducer
函数,这些组合起来的 reducers
将会构成你的应用的状态。
// 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;
}
}
为了将这个状态容器注册到你的应用中,你需要在 AppModule
中导入这个 reducers
,然后在 @NgModule
装饰器的 imports
数组中使用 StoreModule.forRoot
函数。
import { NgModule } from '@angular/core'
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter';
@NgModule({
imports: [
BrowserModule,
StoreModule.forRoot({ count: counterReducer })
]
})
export class AppModule {}
接下来你可以在你的组件或者服务中,注入 Store
服务,并通过 select
操作符来挑选出状态的某一部分。
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
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 });
}
}