首頁  >  文章  >  web前端  >  angular學習之詳解狀態管理器NgRx

angular學習之詳解狀態管理器NgRx

青灯夜游
青灯夜游轉載
2022-05-25 11:01:202546瀏覽

這篇文章帶大家深入了解一下angular的狀態管理器NgRx,介紹一下NgRx的使用方法,希望對大家有幫助!

angular學習之詳解狀態管理器NgRx

NgRx 是 Angular 應用程式中實作全域狀態管理的 Redux 架構解決方案。 【相關教學推薦:《angular教學》】

angular學習之詳解狀態管理器NgRx

  • #@ngrx/store:全域狀態管理模組

  • @ngrx/effects:處理副作用

  • #@ngrx/store-devtools:瀏覽器偵錯工具,需要依賴Redux Devtools Extension

  • #@ngrx/schematics:命令列工具,快速產生NgRx 檔案

  • @ngrx/entity:提高開發者在Reducer 中操作資料的效率

  • @ngrx/router-store:將路由狀態同步到全域Store

#快速開始

1、下載NgRx

npm install @ngrx/store @ngrx/effects @ngrx/entity @ngrx/router-store @ngrx/store-devtools @ngrx/schematics

2、設定NgRx CLI

ng config cli.defaultCollection @ngrx/schematics

// angular.json
"cli": {
  "defaultCollection": "@ngrx/schematics"
}

3、建立Store

ng g store State --root --module app.module.ts --statePath store --stateInterface AppState

##4 、建立Action

ng g action store/actions/counter --skipTests

import { createAction } from "@ngrx/store"

export const increment = createAction("increment")
export const decrement = createAction("decrement")

#5、建立Reducer

#ng g reducer store/reducers/counter --skipTests --reducers=../index.ts

import { createReducer, on } from "@ngrx/store"
import { decrement, increment } from "../actions/counter.actions"

export const counterFeatureKey = "counter"

export interface State {
  count: number
}

export const initialState: State = {
  count: 0
}

export const reducer = createReducer(
  initialState,
  on(increment, state => ({ count: state.count + 1 })),
  on(decrement, state => ({ count: state.count - 1 }))
)

6、建立Selector

#ng g selector store/selectors/counter --skipTests

import { createFeatureSelector, createSelector } from "@ngrx/store"
import { counterFeatureKey, State } from "../reducers/counter.reducer"
import { AppState } from ".."

export const selectCounter = createFeatureSelector<AppState, State>(counterFeatureKey)
export const selectCount = createSelector(selectCounter, state => state.count)

7、元件類別觸發Action、取得狀態

import { select, Store } from "@ngrx/store"
import { Observable } from "rxjs"
import { AppState } from "./store"
import { decrement, increment } from "./store/actions/counter.actions"
import { selectCount } from "./store/selectors/counter.selectors"

export class AppComponent {
  count: Observable<number>
  constructor(private store: Store<AppState>) {
    this.count = this.store.pipe(select(selectCount))
  }
  increment() {
    this.store.dispatch(increment())
  }
  decrement() {
    this.store.dispatch(decrement())
  }
}

8、元件模板顯示狀態

<button (click)="increment()">+</button>
<span>{{ count | async }}</span>
<button (click)="decrement()">-</button>

Action Payload

1、在元件中使用dispatch 觸發Action 時傳遞參數,參數最終會被放置在Action 物件中。

this.store.dispatch(increment({ count: 5 }))

2、建立 Action Creator 函數時,取得參數並指定參數類型。

import { createAction, props } from "@ngrx/store"
export const increment = createAction("increment", props<{ count: number }>())
export declare function props<P extends object>(): Props<P>;

3、在 Reducer 中透過 Action 物件取得參數。

export const reducer = createReducer(
  initialState,
  on(increment, (state, action) => ({ count: state.count + action.count }))
)

MetaReducer

metaReducer 是 Action -> Reducer 之間的鉤子,允許開發者對 Action 進行預處理 (在普通 Reducer 函數呼叫之前呼叫)。

function debug(reducer: ActionReducer<any>): ActionReducer<any> {
  return function (state, action) {
    return reducer(state, action)
  }
}

export const metaReducers: MetaReducer<AppState>[] = !environment.production
  ? [debug]
  : []

Effect

需求:在頁面中新增一個按鈕,點擊按鈕後延遲一秒鐘讓數值增加。

1、在元件模板中新增一個用於非同步數值增加的按鈕,按鈕被點擊後執行

increment_async 方法

<button (click)="increment_async()">async</button>

2、在元件類別中新增

increment_async 方法,並在方法中觸發執行非同步操作的Action

increment_async() {
  this.store.dispatch(increment_async())
}

3、在Action 檔案中新增執行非同步操作的Action

export const increment_async = createAction("increment_async")
4、創建Effect,接收Action 並執行副作用,繼續觸發Action

ng g effect store/effects/counter --root --module app.module.ts --skipTests

Effect 功能由@ngrx/effects 模組提供,所以在根模組中需要導入相關的模組依賴

import { Injectable } from "@angular/core"
import { Actions, createEffect, ofType } from "@ngrx/effects"
import { increment, increment_async } from "../actions/counter.actions"
import { mergeMap, map } from "rxjs/operators"
import { timer } from "rxjs"

// createEffect
// 用于创建 Effect, Effect 用于执行副作用.
// 调用方法时传递回调函数, 回调函数中返回 Observable 对象, 对象中要发出副作用执行完成后要触发的 Action 对象
// 回调函数的返回值在 createEffect 方法内部被继续返回, 最终返回值被存储在了 Effect 类的属性中
// NgRx 在实例化 Effect 类后, 会订阅 Effect 类属性, 当副作用执行完成后它会获取到要触发的 Action 对象并触发这个 Action

// Actions
// 当组件触发 Action 时, Effect 需要通过 Actions 服务接收 Action, 所以在 Effect 类中通过 constructor 构造函数参数的方式将 Actions 服务类的实例对象注入到 Effect 类中
// Actions 服务类的实例对象为 Observable 对象, 当有 Action 被触发时, Action 对象本身会作为数据流被发出

// ofType
// 对目标 Action 对象进行过滤.
// 参数为目标 Action 的 Action Creator 函数
// 如果未过滤出目标 Action 对象, 本次不会继续发送数据流
// 如果过滤出目标 Action 对象, 会将 Action 对象作为数据流继续发出

@Injectable()
export class CounterEffects {
  constructor(private actions: Actions) {
    // this.loadCount.subscribe(console.log)
  }
  loadCount = createEffect(() => {
    return this.actions.pipe(
      ofType(increment_async),
      mergeMap(() => timer(1000).pipe(map(() => increment({ count: 10 }))))
    )
  })
}

Entity

##1、概述Entity 譯為實體,實體就是集合中的一條資料。

NgRx 中提供了實體適配器對象,在實體適配器物件下面提供了各種操作集合中實體的方法,目的就是提高開發者操作實體的效率。

2、核心##1、EntityState:實體類型介面

/*
	{
		ids: [1, 2],
		entities: {
			1: { id: 1, title: "Hello Angular" },
			2: { id: 2, title: "Hello NgRx" }
		}
	}
*/
export interface State extends EntityState<Todo> {}

2、createEntityAdapter: 建立實體適配器物件

3、EntityAdapter:實體適配器物件類型介面

export const adapter: EntityAdapter<Todo> = createEntityAdapter<Todo>()
// 获取初始状态 可以传递对象参数 也可以不传
// {ids: [], entities: {}}
export const initialState: State = adapter.getInitialState()

#3、實例方法

##https://ngrx.io /guide/entity/adapter#adapter-collection-methods

#4、選擇器

##

// selectTotal 获取数据条数
// selectAll 获取所有数据 以数组形式呈现
// selectEntities 获取实体集合 以字典形式呈现
// selectIds 获取id集合, 以数组形式呈现
const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors();
export const selectTodo = createFeatureSelector<AppState, State>(todoFeatureKey)
export const selectTodos = createSelector(selectTodo, selectAll)
#Router Store

1、同步路由狀態

1)引入模組

import { StoreRouterConnectingModule } from "@ngrx/router-store"

@NgModule({
  imports: [
    StoreRouterConnectingModule.forRoot()
  ]
})
export class AppModule {}
2)將路由狀態整合到Store
import * as fromRouter from "@ngrx/router-store"

export interface AppState {
  router: fromRouter.RouterReducerState
}
export const reducers: ActionReducerMap<AppState> = {
  router: fromRouter.routerReducer
}

2、建立取得路由狀態的Selector

// router.selectors.ts
import { createFeatureSelector } from "@ngrx/store"
import { AppState } from ".."
import { RouterReducerState, getSelectors } from "@ngrx/router-store"

const selectRouter = createFeatureSelector<AppState, RouterReducerState>(
  "router"
)

export const {
  // 获取和当前路由相关的信息 (路由参数、路由配置等)
  selectCurrentRoute,
  // 获取地址栏中 # 号后面的内容
  selectFragment,
  // 获取路由查询参数
  selectQueryParams,
  // 获取具体的某一个查询参数 selectQueryParam(&#39;name&#39;)
  selectQueryParam,
  // 获取动态路由参数
  selectRouteParams,
 	// 获取某一个具体的动态路由参数 selectRouteParam(&#39;name&#39;)
  selectRouteParam,
  // 获取路由自定义数据
  selectRouteData,
  // 获取路由的实际访问地址
  selectUrl
} = getSelectors(selectRouter)
// home.component.ts
import { select, Store } from "@ngrx/store"
import { AppState } from "src/app/store"
import { selectQueryParams } from "src/app/store/selectors/router.selectors"

export class AboutComponent {
  constructor(private store: Store<AppState>) {
    this.store.pipe(select(selectQueryParams)).subscribe(console.log)
  }
}
更多程式相關知識,請造訪:程式設計影片! !

以上是angular學習之詳解狀態管理器NgRx的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除