首頁 > web前端 > js教程 > 淺談Angular中使用ngrx做狀態管理的方法

淺談Angular中使用ngrx做狀態管理的方法

青灯夜游
發布: 2021-03-01 10:54:23
轉載
3462 人瀏覽過

淺談Angular中使用ngrx做狀態管理的方法

相關推薦:《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'},

//用户重新登录别的账户为tom

state.username = 'tom'  //在ngrx store 这个行为是绝对不允许的

登入後複製
  • 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

1

yarn add @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;

  // 如果要管理多个状态,在这个接口中添加即可

}

 

//这个是不用接口的情况

// export interface AppState {

//     count: number;

//     todos: any;

//     // 如果要管理多个状态,在这个接口中添加即可

//   }

登入後複製

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

// reducer.ts,一般需要将state,action,reducer进行文件拆分

import { Action } from '@ngrx/store';

 

export const INCREMENT = 'INCREMENT';

export const DECREMENT = 'DECREMENT';

export const RESET = 'RESET';

 

const initialState = 0;

// reducer定义了action被派发时state的具体改变方式

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';

// StoreModule: StoreModule是@ngrx/storeAPI中的一个模块,

// 它被用来在应用模块中配置reducer。

 

import {counterReducer} from './store/reducer';

 

@NgModule({

  imports: [

    StoreModule.forRoot({ count: counterReducer }), // 注册store

  ],

})

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>) { // 注入store

    this.count = store.pipe(select(&#39;count&#39;));

    // 从app.module.ts中获取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>) { // 注入store

    var stream = store.pipe(select(&#39;count&#39;));

    // 从app.module.ts中获取count状态流

    stream.subscribe((res)=>{

          this.count = res;

      })

  }

登入後複製

為了管理方便, 一般會把type , state, actions,reducers 分開來管理

5 如果想把action分離出來如何處理?

  1. 新建\app\store\actions.ts 檔案

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

import { Injectable } from &#39;@angular/core&#39;;

import { INCREMENT, DECREMENT, RESET } from &#39;./types&#39;;

 

@Injectable()

export class CounterAction{

    // Add=function(){}

    Add(){

        return { type: INCREMENT }

    }

}

 

// 就只这样导出是不行的

// export function Add1(){

//     return { type: INCREMENT }

// }

登入後複製
  1. 在根模組app.module.ts 註冊

1

2

3

4

5

import {CounterAction} from &#39;./store/actions&#39;;

 

...

 

providers: [CounterAction],

登入後複製
  1. 在元件中使用– article.component.ts

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

import {CounterAction} from &#39;../../store/actions&#39;;

 

export class ArticleComponent implements OnInit {

 

  constructor(

    private action: CounterAction  //注入CounterAction

    ) { }

 

    increment() {

    // this.store.dispatch({ type: INCREMENT });

    //把 actions分离出去

    this.store.dispatch(this.action.Add());

     

  }

}

登入後複製

更多程式相關知識,請造訪:程式設計影片! !

以上是淺談Angular中使用ngrx做狀態管理的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板