ngrx概念
一個框架用於構建Angular8響應式應用用於狀態管理使用可觀察對象使用Typescript使用OnPush策略,變更檢測更高效狀態序列化存儲易於測試原理圖
簡單入門
初始化項目
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.ts
import { 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.ts
import { 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
<button>Increment/<button>
<button>Decrement/<button>
<button>Reset Counter/<button>
組件觸發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<number>;
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());
}
}/<number>
組件生效
// app.component.html
this is app component
<app-my-counter>
//界面按鈕點擊,觀測數據變化
store.pipe寫法解惑
//查看store源碼,我們得到Observable
export declare class Store extends Observable implements Observer<action> {
....
}/<action>
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.ts
import { 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.ts
import { 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