这篇文章将会示范如何使用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. 5.C++里的4种新型类型转换

    1首先来回顾C的强制转换 大家都知道,在编译C语言中的强制转换时,编译器不会检查转换是否成功,都会编译正确. 比如: #include "stdio.h" struct Posit ...

  2. Spring基础篇——通过Java注解和XML配置装配bean

    自动化装配的确有很大的便利性,但是却并不能适用在所有的应用场景,比如需要装配的组件类不是由自己的应用程序维护,而是引用了第三方的类库,这个时候自动装配便无法实现,Spring对此也提供了相应的解决方案 ...

  3. java生产者与消费者模式

    前言: 生产者和消费者模式是我们在学习多线程中很经典的一个模式,它主要分为生产者和消费者,分别是两个线程, 目录 一:生产者和消费者模式简介 二:生产者和消费者模式的实现 声明:本例来源于java经典 ...

  4. javascript函数大全

    JavaScript函数大全 1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->( ...

  5. Chrome Stylist 插件 (CSS备份)

    Stylist 插件还是很好用的,可以给网站自定义CSS样式,(还有个插件叫"油猴子",可以给网页加载自定义JS): 不过麻烦的是,现在的最新版360浏览器不能显示这个插件(这个浏 ...

  6. 940C Phone Numbers

    传送门 题目大意 给你两个数字n和k,给你一个字符串s,n是s的长度,求字母集合是s的字母集合子集的字典序大于s的长度为k的字典序最小的字符串t 分析 将字符转化为数字,然后分两种情况处理: 1.n& ...

  7. Java中InputStream装饰器模式的大家族

    本文写在po主初学JAVA时,在学习inputStream摸不着头脑,受Java IO-InputStream家族 -装饰者模式一文启发,所以在理清思路时写下本文.因为初学,如有错误,望指正. 因为和 ...

  8. 正本清源区块链——Caoz

    正本清源区块链 说明:以下内容整理自Caoz的<正本清源区块链>,如有不妥,请联系我修改或删除. 简介 不讨论炒币!不讨论炒币!不讨论炒币! 本课程内容分为两部分: 第一部分,烧脑篇,介绍 ...

  9. pinvoke 数据交互笔记

    intptr to array string string[]  _outputStrArray=null;  int channelCount = 0;///返回数组大小            In ...

  10. PHP结合Redis来限制用户或者IP某个时间段内访问的次数

    $redis = new Redis(); $redis->connect('127.0.0.1', 6379); //获取客户端真实ip地址 function get_real_ip(){ s ...