• NgRx/Store 4 + Angular 5使用教程


    Angular.png

    这篇文章将会示范如何使用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

  • 相关阅读:
    一步步构建大型网站架构
    程序员技术练级攻略
    再谈“我是怎么招聘程序员的”
    os.path.basename()
    用pymysql实现的注册登录公告练习
    缓冲(cache)和缓存(buffer)
    数据库视图,触发器,事务,存储过程,函数,备份与恢复
    mysql用户管理和pymysql
    mysql重点,表查询操作和多表查询
    数据库的约束语句和表之间的关系
  • 原文地址:https://www.cnblogs.com/neromaycry/p/8542302.html
Copyright © 2020-2023  润新知