ngrx概念
- 一个框架
- 用于构建Angular8响应式应用
- 用于状态管理
- 使用可观察对象
- 使用Typescript
- 使用OnPush策略,变更检测更高效
- 状态序列化存储
- 易于测试
原理图
![eb71ead809c38447b147b824a15ffd12.png](https://img-blog.csdnimg.cn/img_convert/eb71ead809c38447b147b824a15ffd12.png)
- component产生action(事件)
- action触发effect,业务处理数据
- store中存储state、reducer
- reducer产生新的state
- state修改,更新component
简单入门
初始化项目
ng new ngrx-demo
> ng new ngrx-demo ? Would you like to add Angular routing? Yes? Which stylesheet format would you like to use? SCSS [ https://sass-lang.com/documentation/syntax#scss ]CREATE ngrx-demo/README.md (1026 bytes)CREATE ngrx-demo/.editorconfig (246 bytes)CREATE ngrx-demo/.gitignore (631 bytes)CREATE ngrx-demo/angular.json (3705 bytes)CREATE ngrx-demo/package.json (1295 bytes)CREATE ngrx-demo/tsconfig.json (543 bytes)CREATE ngrx-demo/tslint.json (1953 bytes)CREATE ngrx-demo/browserslist (429 bytes)CREATE ngrx-demo/karma.conf.js (1021 bytes)CREATE ngrx-demo/tsconfig.app.json (270 bytes)CREATE ngrx-demo/tsconfig.spec.json (270 bytes)CREATE ngrx-demo/src/favicon.ico (948 bytes)CREATE ngrx-demo/src/index.html (294 bytes)CREATE ngrx-demo/src/main.ts (372 bytes)....added 1461 packages from 1071 contributors in 85.831s Successfully initialized git.
安装ngrx
npm install @ngrx/store --save
创建Angular组件my-counter
ng generate @schematics/angular:component my-counter --style=scss <
定义action
//app/counter.actions.tsimport { createAction } from '@ngrx/store';export const increment = createAction('[Counter Component] Increment');export const decrement = createAction('[Counter Component] Decrement');export const reset = createAction('[Counter Component] Reset');
定义reducer初始状态为数值
//app/counter.reducer.tsimport { createReducer, on } from '@ngrx/store';import { increment, decrement, reset } from './counter.actions';export const initialState = 0;const _counterReducer = createReducer(initialState, on(increment, state => state + 1), on(decrement, state => state - 1), on(reset, state => 0),);export function counterReducer(state, action) { return _counterReducer(state, action);}
注册state
import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { AppComponent } from './app.component';import { StoreModule } from '@ngrx/store';import { counterReducer } from './counter.reducer';@NgModule({ declarations: [AppComponent], imports: [ BrowserModule, StoreModule.forRoot({ count: counterReducer }) // 注册时指定key ], providers: [], bootstrap: [AppComponent],})export class AppModule {}
定义组件
# app / my-counter / my-counter.component.html
Increment
Current Count: {{ count$ | async }}
DecrementReset Counter
组件触发action
# app / my-counter / my-counter.component.ts
import { Component } from '@angular/core';import { Store, select } from '@ngrx/store';import { Observable } from 'rxjs';import { increment, decrement, reset } from '../counter.actions';@Component({ selector: 'app-my-counter', templateUrl: './my-counter.component.html', styleUrls: ['./my-counter.component.css'],})export class MyCounterComponent { count$: Observable; constructor(private store: Store) { this.count$ = store.pipe(select('count')); //这里关键点,在于app.module.ts注册时候的key } increment() { this.store.dispatch(increment()); } decrement() { this.store.dispatch(decrement()); } reset() { this.store.dispatch(reset()); }}
组件生效
// app.component.html
this is app component
//界面按钮点击,观测数据变化
store.pipe写法解惑
//查看store源码,我们得到Observable export declare class Store extends Observable implements Observer { ....}
store.select也是Observable
export declare function select(mapFn: (state: T, props: Props) => K, props?: Props): (source$: Observable) => Observable;
this.store .select(fromStore.getProductsState) .map(state => state.pizzas) .map(pizzas => pizza.entities);
进阶
当reducer初始状态state为对象时
//counter.reducer.tsimport { createReducer, on } from '@ngrx/store';import { increment, decrement, reset } from './counter.actions';export interface State { away: number;}export const initialState: State = { away: 0,};const _counterReducer = createReducer(initialState, on(increment, state => ({...state, away: state.away + 1})), on(decrement, state => ({...state, away: state.away - 1})), on(reset, state => ({...state, away: 0})),);export function counterReducer(state, action) { return _counterReducer(state, action);}
延迟加载state注册
# 新增文件app/feature.module.tsimport { NgModule } from '@angular/core';import { StoreModule } from '@ngrx/store';import { counterReducer } from './counter.reducer';@NgModule({ imports: [ StoreModule.forFeature('countFeture', counterReducer) # 需要注意,对应的调整 ],})export class ScoreboardModule {}
import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { AppRoutingModule } from './app-routing.module';import { AppComponent } from './app.component';import { StoreModule } from '@ngrx/store';import { counterReducer } from './counter.reducer';import { MyCounterComponent } from './my-counter/my-counter.component';import { ScoreboardModule } from './feature.module';@NgModule({ declarations: [ AppComponent, MyCounterComponent ], imports: [ BrowserModule, AppRoutingModule, StoreModule.forRoot({}), ScoreboardModule ], providers: [], bootstrap: [AppComponent]})export class AppModule { }
参考文献:
- ngrx.io/guide/store
本文作者:前端首席体验师(CheongHu)
联系邮箱:simple2012hcz@126.com