Home  >  Article  >  Web Front-end  >  Detailed explanation of angular learning state manager NgRx

Detailed explanation of angular learning state manager NgRx

青灯夜游
青灯夜游forward
2022-05-25 11:01:202591browse

This article will give you an in-depth understanding of angular's state manager NgRx, and introduce how to use NgRx. I hope it will be helpful to everyone!

Detailed explanation of angular learning state manager NgRx

NgRx is a Redux architecture solution for global state management in Angular applications. [Related tutorial recommendations: "angular tutorial"]

Detailed explanation of angular learning state manager NgRx

  • ##@ngrx/store: Global state management module

  • @ngrx/effects: Handling side effects

  • @ngrx/store-devtools: Browser debugging tool, needs to rely on Redux Devtools Extension

  • @ngrx/schematics: Command line tool to quickly generate NgRx files

  • @ngrx/entity: Improve the efficiency of developers operating data in Reducer

  • @ngrx/router-store: Synchronize routing status to the global Store

Quick start

1. Download NgRx

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

2. Configure NgRx CLI

ng config cli.defaultCollection @ngrx/schematics

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

3. Create Store

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

4 , create Action

ng g action store/actions/counter --skipTests

import { createAction } from "@ngrx/store"

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

5, create 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. Create 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. Component class triggers Action and gets status

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. Component template display status

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

Action Payload

1. Use dispatch in the component to pass parameters when triggering Action, and the parameters will eventually be placed in Action object.

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

2. When creating the Action Creator function, obtain the parameters and specify the parameter type.

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

3. Get parameters through Action object in Reducer.

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

MetaReducer

metaReducer is a hook between Action -> Reducer, allowing developers to preprocess Action (called before ordinary Reducer function calls).

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

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

Effect

Requirement: Add a button to the page, and after clicking the button, delay for one second to increase the value.

1. Add a button for asynchronous value increment in the component template. After the button is clicked, the

increment_async method

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

2. Add a new button in the component class Add the

increment_async method, and trigger the Action

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

in the method to perform the asynchronous operation. 3. Add the Action

export const increment_async = createAction("increment_async")
to the Action file. 4. Create Effect, receive Action and perform side effects, continue to trigger Action

ng g effect store/effects/counter --root --module app.module.ts --skipTests## The #Effect function is provided by the @ngrx/effects module, so the relevant module dependencies need to be imported in the root module

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, OverviewEntity is translated as entity, and entity is a piece of data in the collection.

NgRx provides entity adapter objects. Under the entity adapter objects, various methods for operating entities in the collection are provided. The purpose is to improve the efficiency of developers operating entities.

2. Core1. EntityState: Entity type interface

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

2. createEntityAdapter: Create entity adapter object

3. EntityAdapter: Entity Adapter Object Type Interface

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

3. Instance Methodhttps://ngrx.io /guide/entity/adapter#adapter-collection-methods

4. Selector

// selectTotal 获取数据条数
// selectAll 获取所有数据 以数组形式呈现
// selectEntities 获取实体集合 以字典形式呈现
// selectIds 获取id集合, 以数组形式呈现
const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors();
rrree

Router Store

1. Synchronize routing status1)Introduce module

export const selectTodo = createFeatureSelector<AppState, State>(todoFeatureKey)
export const selectTodos = createSelector(selectTodo, selectAll)

2)Integrate routing status into Store

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

@NgModule({
  imports: [
    StoreRouterConnectingModule.forRoot()
  ]
})
export class AppModule {}

2. Create a Selector to obtain routing status

import * as fromRouter from "@ngrx/router-store"

export interface AppState {
  router: fromRouter.RouterReducerState
}
export const reducers: ActionReducerMap<AppState> = {
  router: fromRouter.routerReducer
}
// 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)
For more programming-related knowledge, please visit:

Programming Video

! !

The above is the detailed content of Detailed explanation of angular learning state manager NgRx. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete