ngrx学习笔记

什么是ngrx
ngrx是Angular基于Rxjs的状态管理,保存了Redux的核心概念,并使用RxJs扩展的Redux实现。使用Observable来简化监听事件和订阅等操作。
在看这篇文章之前,已经假设你已了解rxjs和redux。
有条件的话请查看官方文档进行学习理解。

所需包
ng add方式,会自动生成所需文件并在app.module.ts中导入,直接启动项目即可,不报错
 

ng add @ngrx/store
ng add @ngrx/store-devtools
ng add @ngrx/effects
ng add @ngrx/router-store

Angular的流程

compone.ts定义变量a
改变a
(没有数据请求的) this.a = '';
(有数据请求的) this.a = this.services.search()类似的写法
用ngrx后的Angular的基本流程

写action.ts:为要改变数据的操作定义不同action
写effects.ts(有数据请求的):通过判断action.type,来发起service
写reducer.ts:判断action.type,返回新的store数据
component.ts:从store取数据
最后,告诉应用程序,你写了这玩意

项目简介
本项目的两个demo,都挂在example模块中

计数器-没有数据请求 app/example/container/counter.component.ts
1、先写action(减和重置的action在代码里面,可自行查看)
 

// app/example/actions/counter.actions.ts
import { Action } from '@ngrx/store';export const INCREMENT = '[Counter] Increment';  export class IncrementAction implements Action {readonly type = INCREMENT;constructor() { }
}export type Actions= IncrementAction;

2、写reducer(由于加不需要发送网络请求,就不写effect)

// app/example/reducer/counter.reducer.ts
import * as counter from '../actions/counter.actions';
// 定义接口,后续counter页面如果有其他数据要保存,可以在这个State里面继续添加,不要忘记在initialState也要加
export interface State {counter: number;
}
// 定义初始化数据
const initialState: State = {counter: 0
};
// 定义reducer 根据action type来处理状态,改变对应数据
export function reducer(state = initialState, action: counter.Actions): State {switch (action.type) {case counter.INCREMENT: return {counter: state.counter + 1};default:return { ...state };}
}export const getCounter = (state: State) => state.counter;
// app/example/reducer/index.ts
import {createFeatureSelector, createSelector} from '@ngrx/store';// 第二步 导入我们的reducer文件
import * as fromCounter from './counter.reducer';export interface State {counter: fromCounter.State;
}
export const reducers = {counter: fromCounter.reducer
};//  将模块example的所有数据挂在store上,命名为example,里面保存example模块里面所有页面的数据
export const getExampleState = createFeatureSelector<State>('example');// 计数器页面
export const getCounterState = createSelector(getExampleState, (state: State) => state.counter);
export const getCounterCounter = createSelector(getCounterState, fromCounter.getCounter);

3、在模块中导入reduecer,这样就可以运行

// app/example/example.module.tsimport {StoreModule} from '@ngrx/store';
import {reducers} from './reducer';
@NgModule({imports: [StoreModule.forFeature('example', reducers) // 这个才是关键哦]
})
export class ExampleModule { }

4、到这一步了,我们的页面就来操作并且取数据,增加啦

// src/example/container/counter.component.tsimport * as fromExample from '../../reducer';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import * as counterAction from '../../actions/counter.actions';export class CounterComponent {counter$: Observable<number>;constructor(private store: Store<fromExample.State>) {this.counter$ = store.select(fromExample.getCounterCounter);}increment() {this.store.dispatch(new counterAction.IncrementAction());}
}

页面

// app/example/container/counter.component.html
<div class="container"><p class="title">计数器 没有数据请求的ngrx demo</p><div class="btn-group"><button nz-button nzType="primary" (click)="increment()">加</button><span style="font-size: 18px;font-weight: bold">当前数:{{counter$ | async}}</span></div>
</div>

npm run start看一下页面效果吧

搜索图书-有数据请求的 src/app/example/containers/book-manage/book-manage.component.ts
1、写action (src/app/example/actions/book-manage.actions.ts)看注释

import { Action } from '@ngrx/store';
import {Book} from '../model/book';
// 搜索,然后搜索成功,两件事情,分两个action
export const SEARCH =           '[Book Manage] Search';
export const SEARCH_COMPLETE =  '[Book Manage] Search Complete';
// 搜索图书需要带书名称来搜索,所以SearchAction有一个字符串类型的参数payload
export class SearchAction implements Action {readonly type = SEARCH;constructor(public payload: string) { }
}
// 搜索出结果后,图书的信息我们将其定义类型为Book,结果放在数组里面,所以SearchCompleteAction 的参数是Book类型数组
export class SearchCompleteAction implements Action {readonly type = SEARCH_COMPLETE;constructor(public payload: Book[]) { }
}
export type Actions= SearchAction| SearchCompleteAction;

2、写reducer(src/app/example/reducer/book-manage.reducer.ts)

import * as bookManage from '../actions/book-manage.actions';
import {Book} from '../model/book';
// book-manage页面我们暂时定义一个list变量,用了存搜索图书的结果,后续如果有其他变量,继续在里面加
export interface State {list: Book[];
}
// 默认一开始搜索数据为空数组[]
const initialState: State = {list: []
};
// 当搜索成功后,更新state里面的list值
export function reducer(state = initialState, action: bookManage.Actions): State {switch (action.type) {case bookManage.SEARCH_COMPLETE:return {...state,list: action.payload};default:return { ...state };}
}export const getList = (state: State) => state.list;

3、更新reducer (src/app/example/reducer/index.ts)

import {createFeatureSelector, createSelector} from '@ngrx/store';
import * as fromCounter from './counter.reducer';
// 导入写好的book-manage.reducer.ts
import * as fromBookManage from './book-manage.reducer';  
export interface State {counter: fromCounter.State;bookManage: fromBookManage.State;
}
export const reducers = {counter: fromCounter.reducer,bookManage: fromBookManage.reducer
};
export const getExampleState = createFeatureSelector<State>('example');
// 计数器
export const getCounterState = createSelector(getExampleState, (state: State) => state.counter);
export const getCounterCounter = createSelector(getCounterState, fromCounter.getCounter);
// 图书管理
export const getBookManageState = createSelector(getExampleState, (state: State) => state.bookManage);
export const getBookManageList = createSelector(getBookManageState, fromBookManage.getList);

4、写effect,检测action类型,如果是search图书行为,就发送网络请求查结果(src/app/example/effects/book-manage.effect.ts)

import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {Observable, of} from 'rxjs';
import {Action} from '@ngrx/store';import * as bookManage from '../actions/book-manage.actions';
import {BookManageService} from '../services/book-manage.service';
import {catchError, debounceTime, map, mergeMap, skip, takeUntil} from 'rxjs/operators';
import {BookResult} from '../model/book';@Injectable()
export class BookManageEffects {@Effect()searchBook$: Observable<Action> = this.actions$.pipe(ofType(bookManage.SEARCH),    // 判断是不是搜索图书的行为debounceTime(300),   // 做延迟,节省网络请求mergeMap((action: bookManage.SearchAction) => {const nextSearch$ = this.actions$.pipe(ofType(bookManage.SEARCH), skip(1));return this.service.searchBooks(action.payload).pipe(takeUntil(nextSearch$),// 如果搜索成功,发送成功action并且带入搜索结果map((data: BookResult) => ({type: bookManage.SEARCH_COMPLETE, payload: data.items})),// 如果搜索失败404之类的原因,发送成功action,以及空数组更新结果catchError(() => of({type: bookManage.SEARCH_COMPLETE, payload: []})));}));constructor(private actions$: Actions, private service: BookManageService) {}
}

5、component获取搜索结果和绑定搜索事件(src/app/example/containers/book-manage/book-manage.component.ts)

import { Component, OnInit } from '@angular/core';
import {Store} from '@ngrx/store';
import * as fromExample from '../../reducer';
import * as bookManageAction from '../../actions/book-manage.actions';
import {Observable} from 'rxjs';
import {Book} from '../../model/book';
@Component({selector: 'app-book-manage',templateUrl: './book-manage.component.html',styleUrls: ['./book-manage.component.css']
})
export class BookManageComponent implements OnInit {searchResult$: Observable<Book[]>;  // 搜索到的图书列表constructor(private store: Store<fromExample.State>) {// 从store中选取图书搜索结果this.searchResult$ = this.store.select(fromExample.getBookManageList);}ngOnInit() {}// 发送搜索行为search(bookName) {this.store.dispatch(new bookManageAction.SearchAction(bookName));}}

页面(src/app/example/containers/book-manage/book-manage.component.html)

<div class="container"><app-search-input (search)="search($event)"></app-search-input><app-book-list [bookList]="searchResult$ | async"></app-book-list>
</div>

6、导入effect,否则会不起作用哦 (src/app/example/example.module.ts)

...
import {BookManageEffects} from './effects/book-manage.effect';
import {EffectsModule} from '@ngrx/effects';@NgModule({...imports: [EffectsModule.forFeature([BookManageEffects]),],

ngrx 入门_霞霞的博客的博客-CSDN博客_ngrx文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.slice(0)

高手代码里看到.slice(0)&#xff0c;查了下这样写的好处&#xff1a; 1.对原数组进行深拷贝&#xff0c;这样进行一系列操作的时候就不影响原数组了&#xff1b; 2.将类数组对象转化为真正的数组对象&#xff1a;var anchorArray [].slice.call(document.getElementsByTagN…

亲历2013年TED大会:全球最潮灵感大会

本文转自&#xff1a;http://mooc.guokr.com/opinion/436837/ 本文由《外滩画报》供稿 文/华琪&#xff08;发自美国&#xff09; 编辑/吴慧雯 什么是TED的世界&#xff1f;在这里&#xff0c;你可以轻易发现各种名人出没的痕迹&#xff0c;和各个领域里最具远见卓识和创造…

Java生鲜电商平台-电商会员体系系统的架构设计与源码解析

Java生鲜电商平台-电商会员体系系统的架构设计与源码解析 说明&#xff1a;Java生鲜电商平台中会员体系作为电商平台的基础设施&#xff0c;重要性不容忽视。我去年整理过生鲜电商中的会员系统&#xff0c;但是比较粗&#xff0c;现在做一个最好的整理架构. 设计电商会员体系需…

为什么要上大学?

为了让自己成为更有意思的人。 &#xff08;文&#xff0f;美国圣母大学哲学教授 Gary Gutting&#xff09;再不久&#xff0c;千千万万的大学生又将走完一个学期。他们中的很多人以及他们的家人&#xff0c;可能为刚刚过去的几个月或是几年投入了相当可观的时间、努力以及金钱…

打造“神犇”是教育的未来吗?

这年头&#xff0c;品学兼优、身怀特长的“神犇”&#xff0c;拼的不仅是天赋异禀和后天努力&#xff0c;更是身后爹妈的钱包&#xff0c;而本该实现社会公平的教育&#xff0c;反而加速和凝固了社会的不公。 高等教育的终极目标真的是造就学业超人吗&#xff1f;《纽约时报》刊…

AntD 官网样例 InputRef报错原因

在官网可编辑表格typescript样例里 const inputRef useRef<InputRef>(null); InputRef项目报错原因是ant design的版本问题! antd 4.19版本重写了input 可通过InputRef来使用input组件的ref

AntD 可编辑行表格

本地数据代码模板自用,官网例子改改 // 编辑行的自定义表格 import React, { useState } from "react"; import {Table,Input,InputNumber,Popconfirm,Form,Typography,Divider, } from "antd";interface Item {key: string;name: string;age: number;add…

三心二意,助你好运?

经验说&#xff1a;做事要专心致志。 实验说&#xff1a;专心致志常常让人缺少一双发现的眼睛。 专心致志从来都被当做一个美德来歌颂。从来我们就认为要想成为伟大的人就必须要像牛顿老师那样把钟当成吃的放到锅里煮才行&#xff0c;至少至少也得有能在集市上看书的本事。否则…

React Antd Upload自定义上传customRequest

单独的上传图片接口要传参,action方式不太适合,需要使用自定义上传customRequest覆盖 公司代码不可弄,就发一个可用的demo例子 import React, { useState } from "react"; import { render } from "react-dom"; import "antd/dist/antd.css"; i…

HDU 4109 Instrction Arrangement

题目链接&#xff1a;https://vjudge.net/problem/HDU-4109 题目大意 有 N 个指令&#xff0c;标号从 0 ~ N - 1&#xff0c;和 M 个指令间的先后关系&#xff0c;每个关系都有一个权值 w&#xff0c;表示后一个指令在前一个指令开始时间之后 w 纳秒才开始执行。现在要并发执行…

养成一个习惯需要多久?

有人说养成一个习惯需要21天&#xff0c;有人说30天……养成习惯到底需要多少天&#xff1f; _hzw 2012-11-09 18:04又快到年末了。 年初时&#xff0c;你曾许诺要养成一些好习惯&#xff0c;比如要常运动、多读书、少微博。有人说说养成一个习惯只需要坚持21天&#xff1b;21天…

vue3 eslint The template root requires exactly one element问题

vue项目中手动引入eslint npm install eslint --save-dev eslint初始化 npx eslint --init 运行时npm run lint 简单语法问题--fix会自动修复 但是vue3项目出现只能有一个根节点的问题 原因在于 eslintrc.js里extends中plugin:vue/essential的问题 看eslint-plugin-vue官网…

你所知道的学习方法,都是错的!

你所知道的学习方法&#xff0c;都是错的&#xff01; 上课的时候记笔记&#xff1f;哪门功课不行&#xff0c;就集中精力专项突击&#xff1f;自习的时候不要晃&#xff0c;选好一个地儿安安稳稳地待那儿学习&#xff1f;你还在这样学习吗&#xff1f;不要被骗了&#xff1a;这…

Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲

Java生鲜电商平台-SpringCloud微服务开发中的数据架构设计实战精讲 Java生鲜电商平台: 微服务是当前非常流行的技术框架&#xff0c;通过服务的小型化、原子化以及分布式架构的弹性伸缩和高可用性&#xff0c;可以实现业务之间的松耦合、业务的灵活调整组合以及系统的高可用性…

亚伦•斯沃茨:提升时间的品质

亚伦•斯沃茨&#xff1a;提升时间的品质 不休不眠地工作是低效的&#xff0c;怎样发挥时间的最大效率&#xff1f; 伏维阁主 2013-01-18 16:45图片来源&#xff1a;personalitytutor.com &#xff08;亚伦•斯沃茨Aaron Swartz / 文&#xff09;《 怎样有效利用时间 》中给出的…

Flex4_HttpService组件

1、在JavaWeb项目中新建Servlet(FlexLoginServelt) &#xff1a; public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");response.setContentType("text…

想要提高记忆力?做梦去吧!

想要提高记忆力&#xff1f;做梦去吧&#xff01; 豆豆助 2010-11-26 11:47经验说&#xff1a;不好好学习&#xff0c;就知道睡觉 实验说&#xff1a;要想记忆好&#xff0c;睡觉不能少。做梦可以增强我们的记忆。 有没有办法能让人不费吹灰之力增强记忆力&#xff1f; 做梦吧你…

This beta version of Typora is expired, please download and install a newer version. 解决方案

原文链接&#xff1a;https://blog.csdn.net/yyywxk/article/details/125133205 问题描述 今日打开 Typora 软件时&#xff0c;突然报错&#xff0c;提示软件版本已过期&#xff0c;需要安装新版本&#xff0c;如下图所示。 关闭错误提示框后会自动跳转到&#xff1a;https://…

真想学习?扔掉你详细的计划吧!

真想学习&#xff1f;扔掉你详细的计划吧&#xff01; 该不该定个计划&#xff1f;详细的计划确实可以更高效&#xff0c;也许可以将你减肥的速度加快一倍。但是如果想学习&#xff0c;还是扔掉详细的计划吧&#xff01;因为它会占用你太多的认知资源&#xff0c;只顾着闷头做事…

React Icons

发现一个Icon库,分享下哈; 使用React-Icons轻松地在React项目中包含流行图标&#xff0c;它利用es6导入&#xff0c;允许只包含项目正在使用的图标。 Installation (for standard modern project) npm install react-icons --save Usage import { FaBeer } from react-ico…