这篇文章将会示范如何使用NgRx/Store 4和Angular5。@ngrx/store是基于RxJS的状态管理库,其灵感来源于Redux。在NgRx中,状态是由一个包含action和reducer的函数的映射组成的。Reducer函数经由action的分发以及当前或初始的状态而被调用,最后由reducer返回一个不可变的状态。你可以在@ngrx/store中找到我们将在下面的例子中讨论到的相关的API。

Action: Action是状态的改变。它描述了某个事件的发生,但是没有指定应用的状态如何改变。

ActionReducerMapActionReducerMap注册了一系列的reducer,在应用中使用StoreModule对它进行配置。

ActionReducer: 它被用于创建reducer,例如logger。

MetaReducer: 在应用中使用StoreModule配置的MetaReducer构成了根的meta-reducer。

StoreModule: StoreModule@ngrx/storeAPI中的一个模块,它被用来在应用模块中配置reducer。

createFeatureSelector: 它为状态(state)创建一个feature selector。

createSelector: 它创建一个selector用于生成一个指定的状态。

Store: 它提供了Store.select()Store.dispatch()来与reducer协同工作。Store.select()用于选择一个selector,Store.dispatch()用于向reducer分发action的类型。

1. 使用到的技术

下面是我们的例子中用到的技术:

  1. Angular 5.0.0
  2. Angular CLI 1.5.0
  3. NgRx/Store 4.1.1
  4. TypeScript 2.4.2
  5. Node.js 6.11.0
  6. NPM 3.10.10

2. 安装Angular CLI和NgRX/Store

  1. 确保已安装的Node和NPM的最低版本为:Node 6.9.x和NPM 3.x.x
  2. 在命令行中输入以下命令:
npm install -g @angular/cli
  1. 运行以下命令生成一个新的项目:
ng new my-app
  1. 现在安装@ngrx/store。使用命令行进入my-app目录,然后运行如下命令:
npm i @ngrx/store --save

现在我们已经准备好使用NgRx/Store和Angular了。

3. 创建State

State是一个单独的不可变的数据结构。我们会像如下这样创建state:

export interface AppState {
articleState: ArticleState;
}
export interface ArticleState {
articles: Article[];
}

4. 创建Action类

NgRx的Action描述了状态的变化。对于每一个action,我们都需要创建一个继承自Action的类,同时定义其type和payload(payload是个可选参数)。

export const JAVA = 'Java';
export const MY_ARTICLES = 'Favorite_Articles'; export class JavaArticlesAction implements Action {
readonly type = JAVA;
}
export class FavoriteArticlesAction implements Action {
readonly type = MY_ARTICLES; constructor(public payload: Article[]) {}
}

5. 创建Reducer

Reducer描述了任何一个action所对应的应用的state将怎样变化。reducer创建如下:


export function reducer(state = initialState, action: fromActions.All): ArticleState {
switch(action.type) {
case fromActions.JAVA: {
return {articles: JAVA_ARTICLES};
}
case fromActions.ANGULAR: {
return {articles: ANGULAR_ARTICLES}; }
case fromActions.MY_ARTICLES: {
return {articles: action.payload};
}
default: {
return state;
}
}
}

6. 使用createFeatureSelector和createSelector()

createFeatureSelector()被用于为任意指定的state创建一个feature selector。

export const getArticleState = createFeatureSelector<ArticleState>('articleState');

createSelector()使用feature selector来创建selector。

export const getArticles = createSelector(
getArticleState,
(state: ArticleState) => state.articles
);

7. 使用ActionReducerMap

ActionReducerMap注册了reducer。我们需要在我们配置我们的reducer的地方创建一个 ActionReducerMap的常量。然后在应用模块中使用StoreModule来配置这个常量。

export const reducers: ActionReducerMap<AppState> = {
articleState: articleReducer.reducer
};

8.使用ActionReducer

ActionReducer用来创建类似logger的reducer,使用MetaReducer对它进行配置。

export function logger(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
return function(state: AppState, action: any): AppState {
console.log('state', state);
console.log('action', action);
return reducer(state, action);
};
}

通过使用上面的代码,我们可以在控制台中获取每个action的状态和名称。

9.使用MetaReducer

MetaReducer由我们所创建的一系列ActionReducer所组成。在应用中使用StoreModule配置的MetaReducer构成了根meta-reducer。@ngrx/store默认使用 combineReducers在创建根meta-reducer。

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

10. 使用StoreModule

StoreModule@ngrx/storeAPI中的一个模块,它被用来在应用模块中配置reducer。

@NgModule({
imports: [
---
StoreModule.forRoot(reducers, {metaReducers})
]
---
})

11. 使用Store.select()Store.dispatch()

Store.select()Store.dispatch()与是reducer配合使用的。Store.select()用于选择一个selector,Store.dispatch()用于向reducer分发action的类型。

要使用Store, 在组件中创建一个Observable类型的属性。

articles: Observable<Article[]>

现在使用依赖注入来实例化Store,然后选择一个selector。

constructor(private store: Store<ArticleState>) {
this.articles = store.select(articleReducer.getArticles);
}

现在分发这个action以通过reducer改变state。

showJavaArticles(){
this.store.dispatch(new fromActions.JavaArticlesAction());
}

12. 完整的例子

下面是我们的例子的项目结构:

my-app
|
|--src
| |
| |--app
| | |
| | |--actions
| | | |
| | | |--article.actions.ts
| | |
| | |--components
| | | |
| | | |--article.component.html
| | | |--article.component.ts
| | |
| | |--models
| | | |
| | | |--article.ts
| | |
| | |--reducers
| | | |
| | | |--app.states.ts
| | | |--article.reducer.ts
| | | |--reducers.ts
| | |
| | |--app.component.ts
| | |--app.module.ts
| |
| |--main.ts
| |--index.html
| |--styles.css
|
|--node_modules
|--package.json

以下是完整的代码:

article.actions.ts

import { Action } from '@ngrx/store';
import { Article } from '../models/article'; export const JAVA = 'Java';
export const ANGULAR = 'Angular';
export const MY_ARTICLES = 'Favorite_Articles'; export class JavaArticlesAction implements Action {
readonly type = JAVA;
} export class AngularArticlesAction implements Action {
readonly type = ANGULAR;
} export class FavoriteArticlesAction implements Action {
readonly type = MY_ARTICLES; constructor(public payload: Article[]) {}
} export type All = JavaArticlesAction | AngularArticlesAction | FavoriteArticlesAction;

article.ts

export interface Article {
id: number;
title: string;
category: string;
} export const JAVA_ARTICLES: Article[] = [
{id: 1, title: 'Java Article 1', category: 'Java'},
{id: 2, title: 'Java Article 2', category: 'Java'},
]
export const ANGULAR_ARTICLES: Article[] = [
{id: 1, title: 'Angular Article 1', category: 'Angular'},
{id: 2, title: 'Angular Article 2', category: 'Angular'},
]
export const FAVORITE_ARTICLES: Article[] = [
{id: 1, title: 'Java Article 1', category: 'Java'},
{id: 2, title: 'Angular Article 2', category: 'Angular'}
]

app.states.ts

import { Article } from '../models/article';

export interface AppState {
articleState: ArticleState;
} export interface ArticleState {
articles: Article[];
}

article.reducer.ts

import { createFeatureSelector, createSelector } from '@ngrx/store';
import * as fromActions from '../actions/article.actions';
import { JAVA_ARTICLES, ANGULAR_ARTICLES } from '../models/article';
import { ArticleState } from './app.states'; export const initialState: ArticleState = { articles: []}; export function reducer(state = initialState, action: fromActions.All): ArticleState {
switch(action.type) {
case fromActions.JAVA: {
return {articles: JAVA_ARTICLES};
}
case fromActions.ANGULAR: {
return {articles: ANGULAR_ARTICLES}; }
case fromActions.MY_ARTICLES: {
return {articles: action.payload};
}
default: {
return state;
}
}
} export const getArticleState = createFeatureSelector<ArticleState>('articleState'); export const getArticles = createSelector(
getArticleState,
(state: ArticleState) => state.articles
);

reducer.ts

import { ActionReducerMap, ActionReducer, MetaReducer } from '@ngrx/store';
import { AppState } from './app.states';
import * as articleReducer from './article.reducer';
import { environment } from '../../environments/environment'; export const reducers: ActionReducerMap<AppState> = {
articleState: articleReducer.reducer
}; export function logger(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
return function(state: AppState, action: any): AppState {
console.log('state', state);
console.log('action', action);
return reducer(state, action);
};
} export const metaReducers: MetaReducer<AppState>[] = !environment.production
? [logger]
: [];

article.component.ts

import { Store } from '@ngrx/store';
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import * as articleReducer from '../reducers/article.reducer';
import * as fromActions from '../actions/article.actions';
import { ArticleState } from '../reducers/app.states';
import { Article, FAVORITE_ARTICLES } from '../models/article'; @Component({
selector: 'app-article',
templateUrl: 'article.component.html'
})
export class ArticleComponent {
articles: Observable<Article[]> constructor(private store: Store<ArticleState>) {
this.articles = store.select(articleReducer.getArticles);
}
showJavaArticles(){
this.store.dispatch(new fromActions.JavaArticlesAction());
}
showAngularArticles(){
this.store.dispatch(new fromActions.AngularArticlesAction());
}
showFavoriteArticles(){
this.store.dispatch(new fromActions.FavoriteArticlesAction(FAVORITE_ARTICLES));
}
}

article.component.html

<button (click)="showJavaArticles()">Java Articles</button>
<button (click)="showAngularArticles()">Angular Articles</button>
<button (click)="showFavoriteArticles()">Favorite Articles</button>
<ul>
<li *ngFor="let article of articles | async">
{{article.id}} - {{article.title}} - {{article.category}}
</li>
</ul>

app.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
template: `
<app-article></app-article>
`
})
export class AppComponent {
}

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { AppComponent } from './app.component';
import { ArticleComponent } from './components/article.component';
import { reducers, metaReducers } from './reducers/reducers'; @NgModule({
imports: [
BrowserModule,
StoreModule.forRoot(reducers, {metaReducers})
],
declarations: [
AppComponent,
ArticleComponent
],
providers: [ ],
bootstrap: [
AppComponent
]
})
export class AppModule { }

下载源代码

原文地址:NgRx/Store 4 + Angular 5 Tutorial

本文由本人原创翻译,转载请注明出处:https://www.jianshu.com/p/c2d61fc76128

NgRx/Store 4 + Angular 5使用教程的更多相关文章

  1. [Angular 2] ngrx/store

    @ngrx/store builds on the concepts made popular by Redux and supercharges it with the backing of RxJ ...

  2. [Angular 2] Using ngrx/store and Reducers for Angular 2 Application State

    ngrx/store is a library that simplifies common RxJS patterns for managing state and gives you an eas ...

  3. Angular应用架构设计-3:Ngrx Store

    这是有关Angular应用架构设计系列文章中的一篇,在这个系列当中,我会结合这近两年中对Angular.Ionic.甚至Vuejs等框架的使用经验,总结在应用设计和开发过程中遇到的问题.和总结的经验, ...

  4. ngrx/store effects 使用总结1:计数器

    本教程案例github:https://github.com/axel10/ngrx_demo-counter-and-list angular2+ 的学习成本应该是三大框架中最高的一个,教程及案例稀 ...

  5. [Angular] Extract Implementation Details of ngrx from an Angular Application with the Facade Pattern

    Extracting away the implementation details of ngrx from your components using the facade pattern cre ...

  6. ngrx/store effects 使用总结2:列表展示

    第一个计数器案例:http://www.cnblogs.com/axel10/p/8589122.html 完成了计数器案例后,现在开始比较能够完整的展示angular2+开发流程的案例:在线获取用户 ...

  7. Angular CLI 使用教程指南参考

    Angular CLI 使用教程指南参考 Angular CLI 现在虽然可以正常使用但仍然处于测试阶段. Angular CLI 依赖 Node 4 和 NPM 3 或更高版本. 安装 要安装Ang ...

  8. [Angular2] @Ngrx/store and @Ngrx/effects learning note

    Just sharing the learning experience related to @ngrx/store and @ngrx/effects. In my personal opinio ...

  9. Angular 英雄示例教程

    英雄指南教程(Tour of Heroes)涵盖了 Angular 的基本知识. 在本教程中,你将构建一个应用,来帮助人事代理机构来管理一群英雄. 这个入门级 app 包含很多数据驱动的应用所需的特性 ...

随机推荐

  1. b继承a

    有下面这样的一段代码: function a(){ this.foo = function(){ console.log('foo'); } } var b = {}; 请问如何让b继承a? b.__ ...

  2. 在CentOS 6.x上配合Windows客户端搭建 git(gitosis)服务器

    一.在 CentOS 上安装 git 和 gitosis: 逐条执行如下语句: sudo yum install git python-setuptools cd /opt sudo git clon ...

  3. hiveql笔记(一)

    1.创建表 create table if not exists mydb.employees{ name String COMMENT 'Employee name', salary FLOAT C ...

  4. 如何在Centos 7上用Logrotate管理日志文件

    何为Logrotate? Logrotate是一个实用的日志管理工具,旨在简化对系统上生成大量的日志文件进行管理. Logrotate允许自动旋转压缩,删除和邮寄日志文件,从而节省宝贵的磁盘空间. L ...

  5. MySQL对sum()字段 进行条件筛选,使用having,不能用where

    显示每个地区的总人口数和总面积.仅显示那些面积超过1000000的地区. SELECT region, SUM(population), SUM(area) FROM bbc GROUP BY reg ...

  6. POJ 1023 The Fun Number System

    Description In a k bit 2's complement number, where the bits are indexed from 0 to k-1, the weight o ...

  7. hdu3480 Division(dp平行四边形优化)

    题意:将n个数分成m段,每段的代价为最大值减最小值的平方,为代价最小是多少n<=10000 ,m<=5000 题解:先拍好序,从小到大,这样绝对是花费最小的,不过怎么样来做呢?一定很容易想 ...

  8. bzoj 3048[Usaco2013 Jan]Cow Lineup 思想,乱搞 stl

    3048: [Usaco2013 Jan]Cow Lineup Time Limit: 2 Sec  Memory Limit: 128 MBSubmit: 237  Solved: 168[Subm ...

  9. Asp.Net Core Identity+EFCore + Mysql踩坑记录

    搭建基础框架准备试试传说中的Identity,本以为很顺利,结果一路踩了N多坑 遂就把过程记录下来.方便自己以后查看,也希望能帮到遇到同样问题的朋友. 1.首先,引入Identity需要的类库,还有M ...

  10. hdu1496 打表

    通常可以想到直接四个for枚举,但是会超时.就算只用三个for也很危险.可以用打表的方法将时间复杂度降到O(n^2),注意到x1,x2,x3,x4的取值区间是关于零对称的,因此可以只考虑正整数部分,洗 ...