这篇文章将会示范如何使用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. opencv-python与c++ opencv中的一些区别和基础的知识

    使用opencv-python一段时间了,因为之前没有大量接触过c++下的opencv,在网上看c++的一些程序想改成python遇到了不少坑,正好在这里总结一下. 1.opencv 中x,y,hei ...

  2. ASCII Art (English)

    Conmajia, 2012 Updated on Feb. 18, 2018 What is ASCII art? It's graphic symbols formed by ASCII char ...

  3. 11个phpstorm 快捷键介绍

    11个phpstorm 快捷键介绍 http://phpstorm.tips/tips/11-toggling-case

  4. LeetCode - 627. Swap Salary

    Given a table salary, such as the one below, that has m=male and f=female values. Swap all f and m v ...

  5. C#小笔记:单例模式

    双重锁定: public class Singleton { private static Singleton instance; private static readonly object syn ...

  6. java使用*导包的性能

    项目中切换到IDEA工具,使用Git提交代码之后在comments中被吐槽了.事情是这样的原有的导入包被IDEA优化了,譬如java.util.Set, java.util.Map, ... 会被优化 ...

  7. 使用supervisor 进行进程管理时调整最大文件打开数

    [supervisord]logfile=/tmp/supervisord.log ; 日志文件,默认是 $CWD/supervisord.loglogfile_maxbytes=50MB ; 日志文 ...

  8. 基于agenda的Nodejs定时任务管理框架搭建

    0.背景 在大型项目中,定时任务的应用场景越来越广.一般来说,按照微服务的思想,我们会将定时任务单独部署一套服务,核心的业务接口独立到另一个服务中,从而降低相互之间的耦合程度.在需要使用定时任务时,只 ...

  9. C#委托与事件--简单笔记

    委托 简单记录点东西 适合似懂非懂的朋友看看 委托类型用来定义和响应应用程序中的回调. 借此可以设计各种有面向对象特性的代码模式.下面要说的事件在我看来就是委托的一种实现,再深一步讲,利用委托加事件, ...

  10. Java8的一些新特性

    速度更快: 代码更少(增加了新的语法Lamdba表达式): Lamdba操作符"->" 语法格式: 左侧:参数列表 右侧:接口抽象方法的实现功能 Lamdba表达式 3.强大 ...