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

Detailed explanation of angular learning state manager NgRx

青灯夜游
Release: 2022-05-25 11:01:20
forward
2712 people have browsed it

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"
}
Copy after login

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")
Copy after login

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 }))
)
Copy after login

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)
Copy after login

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())
  }
}
Copy after login

8. Component template display status

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

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 }))
Copy after login

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 }>())
Copy after login
export declare function props<P extends object>(): Props<P>;
Copy after login

3. Get parameters through Action object in Reducer.

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

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]
  : []
Copy after login

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>
Copy after login

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())
}
Copy after login

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

export const increment_async = createAction("increment_async")
Copy after login

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 }))))
    )
  })
}
Copy after login

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> {}
Copy after login

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()
Copy after login

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();
Copy after login
rrree

Router Store

1. Synchronize routing status1)Introduce module

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

2)Integrate routing status into Store

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

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

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
}
Copy after login
// 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)
Copy after login
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!

Related labels:
source:csdn.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template