这篇文章将会示范如何使用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. 2018/1/19 Netty学习笔记(一)

    这段时间学了好多好多东西,不过更多是细节和思想上的,比如分布式事物,二次提交,改善代码质量,还有一些看了一些源码什么的; 记录一下真正的技术学习,关于Netty的学习过程; 首先说Netty之前先说一 ...

  2. PHP实现session对象封装

    <?php class Session { private $db; // 设置数据库变量 private $expiry = 3600; // 设置Session失效时间 public fun ...

  3. 广告中的AdNetwork、AdExchange、DSP、SSP、RTB和DMP是什么?

    [https://www.douban.com/note/557732418/?type=rec] AdNetwork.AdExchange.DSP.SSP.RTB.DMP这些模式之间存在着内在的关系 ...

  4. mac下自带的Apache+PHP环境输出错误提示

    sudo vim /etc/php.ini 找到 display_errors = Off ,把Off 改为 On . 最后为 display_errors = On ; 找到 error_repor ...

  5. 一个web应用的诞生(1)--初识flask

    基于flask的web应用的诞生 Flask是一个非常优秀的web框架,它最大的特点就是保持一个简单而易于扩展的小核心,其他的都有用户自己掌握,并且方便替换,甚至,你可以在社区看到众多开源的,可直接用 ...

  6. MySQL数据库基础(MySQL5.7安装、配置)

      写在前面: MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQ ...

  7. CentOS Crontab(定时任务)

    安装crontab: yum install crontabs 说明: service crond start //启动服务 service crond stop //关闭服务 service cro ...

  8. java基础--面对对象

    面对对象--概述 什么是对象? +---->对象可以泛指一切现实中存着的事物 +---->类是对象的抽象集合 什么是面对对象? +--->万物皆对象,面对对象实际就是人与万物接触== ...

  9. Spring Boot 2.0(二):Spring Boot 2.0尝鲜-动态 Banner

    Spring Boot 2.0 提供了很多新特性,其中就有一个小彩蛋:动态 Banner,今天我们就先拿这个来尝尝鲜. 配置依赖 使用 Spring Boot 2.0 首先需要将项目依赖包替换为刚刚发 ...

  10. POJ - 2387 最短路

    思路:用dijkstra算法,是无向图. AC代码: #include <cstdio> #include <cmath> #include <cctype> #i ...