
相關推薦:《angular教學》
#ngrx/store的靈感來自Redux,是一款整合RxJS的Angular狀態管理庫,由Angular的佈道者Rob Wormald開發。它和Redux的核心思想相同,但使用RxJS實現觀察者模式。它遵循Redux核心原則,但專門為Angular而設計。
Angular中的狀態管理大部分可以被service接管,那麼在一些中大型的專案中,這樣做的弊端就會顯露出來,其中之一就是狀態流混亂,不利於後期維護,後來便藉鑒了redux的狀態管理模式並配上rxjs串流程式設計的特點形成了@ngrx/store這麼一個作用於Angular的狀態管理工具.
StoreModule:
StoreModule是@ngrx/store API中的一個模組,它被用來在應用程式模組中配置reducer。
Action:
Action是狀態的改變。它描述了某個事件的發生,但是沒有指定應用的狀態如何改變。
Store:
它提供了Store.select()和Store.dispatch()來與reducer協同工作。 Store.select()用來選擇一個selector,
Store.dispatch(
{
type:'add',
payload:{name:'111'}
}
)
用來向reducer分發action的類型。
@NgRx/Store 狀態管理的三個原則
首先,@NgRx/Store 同樣遵守Redux 的三個基本原則:
這個原則是整個單頁應用的狀態透過object tree(物件樹)的形式儲存在store 裡面。
這個定義十分抽像其實就是把所有需要共享的資料透過javascript 物件的形式儲存下來
1 2 3 4 5 | state =
{
application: 'angular app' ,
shoppingList:[ 'apple' , 'pear' ]
}
|
登入後複製
- state is read-only(狀態只能是唯讀形式)
#這個ngrx/store 核心之一就是使用者不能直接修改狀態內容。舉個例子,如果我們需要儲存了登入頁面狀態,狀態資訊需要記錄登入使用者的名字。當登入名字改變,我們不能直接修改狀態保存的使用者名字
1 2 3 | state={ 'username' : 'kat' },
state.username = 'tom'
|
登入後複製
- changes are made with pure functions(只能透過呼叫函數來改變狀態)
由於不能直接需改狀態,ngrx/store 同時引進了一個叫做reducer(聚合器)的概念。透過reducer 來修改狀態。
1 2 3 4 5 6 7 8 | function reducer(state = 'SHOW_ALL' , action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER' :
return Object.assign({}, state ,newObj);
default :
return state
}
}
|
登入後複製
ngrx/store使用實例
#1.安裝 @ngrx/store
2. 創建state, action, reducer
state 狀態:
app\store\state.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | export interface TaskList {
id: number;
text: string;
complete: boolean;
}
export const TASKSAll: TaskList[] = [
{id: 1, text: 'Java Article 1', complete: false},
{id: 2, text: 'Java Article 2', complete: false}
]
export interface AppState {
count : number;
todos: TaskList;
}
|
登入後複製
reducer
app\store\reducer.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import { Action } from '@ngrx/store';
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';
const initialState = 0;
export function counterReducer(state: number = initialState, action: Action) {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
case RESET:
return 0;
default :
return state;
}
}
|
登入後複製
actions
#如果需要把action 單獨提取出來, 參考後面的
5 如果想把action分離出來如何處理?
3. 註冊store
根模組:
app/app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import {counterReducer} from './store/reducer';
@NgModule({
imports: [
StoreModule.forRoot({ count : counterReducer }),
],
})
export class AppModule {}
|
登入後複製
4. 使用store
在元件或服務中註入store進行使用
以app\module\article\article.component.ts 元件為例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import { Component } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';
import { INCREMENT, DECREMENT, RESET} from '../../store/reducer';
interface AppState {
count : number;
}
@Component({
selector: 'app-article',
templateUrl: './article.component.html',
styleUrls: ['./article.component.css']
})
export class ArticleComponent {
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 });
}
}
|
登入後複製
範本頁面:
app\module\article\article.component.html
1 2 3 4 5 6 7 8 | <div class = "state-count" >
<button (click)= "increment()" >增加Increment</button>
<div>Current Count : {{ count | async }}</div>
<button (click)= "decrement()" >减少Decrement</button>
<button (click)= "reset()" >Reset Counter</button>
</div>
|
登入後複製
這裡使用了管道符async, 在子模組裡直接使用快報錯, 如果在子模組要實現資料的雙向綁定也會報錯,具體原因參考課件說明的問題: The pipe 'async' could not be found?
如何做到在範本頁面中不使用管道 來渲染頁面 ?
修改如下:
1 2 3 4 5 6 7 8 9 | count : Observable<number>;
constructor( private store: Store<AppState>) {
var stream = store.pipe(select(' count '));
stream.subscribe((res)=>{
this. count = res;
})
}
|
登入後複製
為了管理方便, 一般會把type , state, actions,reducers 分開來管理
5 如果想把action分離出來如何處理?
- 新建\app\store\actions.ts 檔案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { Injectable } from '@angular/core';
import { INCREMENT, DECREMENT, RESET } from './types';
@Injectable()
export class CounterAction{
Add(){
return { type: INCREMENT }
}
}
|
登入後複製
- 在根模組app.module.ts 註冊
1 2 3 4 5 | import {CounterAction} from './store/actions';
...
providers: [CounterAction],
|
登入後複製
- 在元件中使用– article.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import {CounterAction} from '../../store/actions';
export class ArticleComponent implements OnInit {
constructor(
private action: CounterAction
) { }
increment() {
this.store.dispatch(this.action.Add());
}
}
|
登入後複製
更多程式相關知識,請造訪:程式設計影片! !
以上是淺談Angular中使用ngrx做狀態管理的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!