溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Angular怎么使用ngrx/store做狀態(tài)管理

發(fā)布時(shí)間:2021-01-22 09:20:11 來(lái)源:億速云 閱讀:519 作者:小新 欄目:web開(kāi)發(fā)

小編給大家分享一下Angular怎么使用ngrx/store做狀態(tài)管理,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

Angular中使用ngrx做狀態(tài)管理

簡(jiǎn)介

ngrx/store的靈感來(lái)源于Redux,是一款集成RxJS的Angular狀態(tài)管理庫(kù),由Angular的布道者Rob Wormald開(kāi)發(fā)。它和Redux的核心思想相同,但使用RxJS實(shí)現(xiàn)觀察者模式。它遵循Redux核心原則,但專(zhuān)門(mén)為Angular而設(shè)計(jì)。

Angular中的狀態(tài)管理大部分可以被service接管,那么在一些中大型的項(xiàng)目中,這樣做的弊端就會(huì)顯露出來(lái),其中之一就是狀態(tài)流混亂,不利于后期維護(hù),后來(lái)便借鑒了redux的狀態(tài)管理模式并配上rxjs流式編程的特點(diǎn)形成了@ngrx/store這么一個(gè)作用于Angular的狀態(tài)管理工具.

  • StoreModule:
    StoreModule是@ngrx/store API中的一個(gè)模塊,它被用來(lái)在應(yīng)用模塊中配置reducer。

  • Action:
    Action是狀態(tài)的改變。它描述了某個(gè)事件的發(fā)生,但是沒(méi)有指定應(yīng)用的狀態(tài)如何改變。

  • Store:
    它提供了Store.select()和Store.dispatch()來(lái)與reducer協(xié)同工作。Store.select()用于選擇一個(gè)selector,
    Store.dispatch(
    {
    type:‘a(chǎn)dd’,
    payload:{name:‘111’}
    }
    )
    用于向reducer分發(fā)action的類(lèi)型。

@NgRx/Store 狀態(tài)管理的三個(gè)原則

首先,@NgRx/Store 同樣遵守 Redux 的三個(gè)基本原則:

  • 單一數(shù)據(jù)源

這個(gè)原則是整個(gè)單頁(yè)應(yīng)用的狀態(tài)通過(guò)object tree(對(duì)象樹(shù))的形式存儲(chǔ)在store 里面。
這個(gè)定義十分抽象其實(shí)就是把所有需要共享的數(shù)據(jù)通過(guò)javascript 對(duì)象的形式存儲(chǔ)下來(lái)

state =
{
    application:'angular app',
    shoppingList:['apple', 'pear']
}
  • state is read-only(狀態(tài)只能是只讀形式)

這個(gè) ngrx/store 核心之一就是用戶(hù)不能直接修改狀態(tài)內(nèi)容。 舉個(gè)例子,如果我們需要保存了登錄頁(yè)面狀態(tài),狀態(tài)信息需要記錄登錄用戶(hù)的名字。 當(dāng)?shù)卿浢指淖?,我們不能直接修改狀態(tài)保存的用戶(hù)名字

state={'username':'kat'},
//用戶(hù)重新登錄別的賬戶(hù)為tom
state.username = 'tom'  //在ngrx store 這個(gè)行為是絕對(duì)不允許的
  • changes are made with pure functions(只能通過(guò)調(diào)用函數(shù)來(lái)改變狀態(tài))

由于不能直接需改狀態(tài),ngrx/store 同時(shí)引入了一個(gè)叫做reducer(聚合器)的概念。通過(guò)reducer 來(lái)修改狀態(tài)。

function reducer(state = 'SHOW_ALL', action) {
    switch (action.type) {
      	case 'SET_VISIBILITY_FILTER':
        	return Object.assign({}, state  ,newObj);  
        default:
        	return state  
        }
	}

ngrx/store使用實(shí)例

1.安裝@ngrx/store

yarn add @ngrx/store

2. 創(chuàng)建 state, action, reducer

state 狀態(tài):
app\store\state.ts

//下面是使用接口的情況, 更規(guī)范
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;
  // 如果要管理多個(gè)狀態(tài),在這個(gè)接口中添加即可
}

//這個(gè)是不用接口的情況
// export interface AppState {
//     count: number;
//     todos: any;
//     // 如果要管理多個(gè)狀態(tài),在這個(gè)接口中添加即可
//   }

reducer
app\store\reducer.ts

// reducer.ts,一般需要將state,action,reducer進(jìn)行文件拆分
import { Action } from '@ngrx/store';

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';

const initialState = 0;
// reducer定義了action被派發(fā)時(shí)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

如果需要把a(bǔ)ction 單獨(dú)提取出來(lái), 參考 后面的
5 如果想把a(bǔ)ction分離出來(lái)如何處理?

3. 注冊(cè)store

根模塊:
app/app.module.ts

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
// StoreModule: StoreModule是@ngrx/storeAPI中的一個(gè)模塊,
// 它被用來(lái)在應(yīng)用模塊中配置reducer。

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

@NgModule({
  imports: [
  	StoreModule.forRoot({ count: counterReducer }), // 注冊(cè)store
  ],
})
export class AppModule {}

4. 使用store

在組件或服務(wù)中注入store進(jìn)行使用

以 app\module\article\article.component.ts 組件為例:

// 組件級(jí)別
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('count')); 
    // 從app.module.ts中獲取count狀態(tài)流
  }

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

  decrement() {
    this.store.dispatch({ type: DECREMENT });
  }

  reset() {
    this.store.dispatch({ type: RESET });
  }
}

模板頁(yè)面:
app\module\article\article.component.html

<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, 在子模塊里直接使用快報(bào)錯(cuò) , 如果在子模塊要實(shí)現(xiàn) 數(shù)據(jù)的雙向綁定也會(huì)報(bào)錯(cuò),具體原因參照 課件說(shuō)明的 問(wèn)題: The pipe ‘a(chǎn)sync’ could not be found?

如何做到在模板頁(yè)面中不使用管道 來(lái)渲染頁(yè)面 ?

修改如下:

count: Observable<number>;

constructor(private store: Store<AppState>) { // 注入store
    var stream = store.pipe(select('count')); 
    // 從app.module.ts中獲取count狀態(tài)流
    stream.subscribe((res)=>{
          this.count = res;
      })
  }

為了管理方便, 一般會(huì)把 type , state, actions,reducers 分開(kāi)來(lái)管理

5 如果想把a(bǔ)ction分離出來(lái)如何處理?

  1. 新建 \app\store\actions.ts 文件

import { Injectable } from '@angular/core';
import { INCREMENT, DECREMENT, RESET } from './types';

@Injectable()
export class CounterAction{
    // Add=function(){}
    Add(){
        return { type: INCREMENT }
    }
}

// 就只這樣導(dǎo)出是不行的
// export function Add1(){
//     return { type: INCREMENT }
// }
  1. 在根模塊 app.module.ts 注冊(cè)

import {CounterAction} from './store/actions';

... 

providers: [CounterAction],
  1. 在組件中使用 – article.component.ts

import {CounterAction} from '../../store/actions';

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/store做狀態(tài)管理”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI