ngrx 是 angular 应用中实现全局状态管理的 redux 架构解决方案。【相关教程推荐:《angular教程》】
@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 payload1、在组件中使用 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 })))
metareducermetareducer 是 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 })))) ) })}
entity1、概述
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 store1、同步路由状态
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.tsimport { 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('name') selectqueryparam, // 获取动态路由参数 selectrouteparams, // 获取某一个具体的动态路由参数 selectrouteparam('name') selectrouteparam, // 获取路由自定义数据 selectroutedata, // 获取路由的实际访问地址 selecturl} = getselectors(selectrouter)
// home.component.tsimport { 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的详细内容。
