天天看点

Angular中使用ngrx/store做状态管理

引入

Angular

中的状态管理大部分可以被

service

接管,那么在一些中大型的项目中,这样做的弊端就会显露出来,其中之一就是状态流混乱,不利于后期维护,后来便借鉴了

redux

的状态管理模式并配上

rxjs

流式编程的特点形成了

@ngrx/store

这么一个作用于Angular的状态管理工具.

状态管理的三个原则

状态管理三个原则引用自 vjjy001 状态管理
  • Single source of truth

    (单一状态对象)

    这个原则是整个单页应用的状态通过object tree(对象树)的形式存储在store 里面。这个定义十分抽象其实就是把所有需要共享的数据通过javascript 对象的形式存储下来

state =
{
    application:'angular app',
    shoppingList:['apple', 'pear']
}
           
  • state is read-only

    (状态只能是只读形式)

    这个 ngrx/store 核心之一就是用户不能直接修改状态内容。 举个例子,如果我们需要保存了登录页面状态,状态信息需要记录登录用户的名字。 当登录名字改变,我们不能直接修改状态保存的用户名字

state={'username':'kat'},
//用户重新登录别的账户为tom
state.username = 'tom'  //在ngrx store 这个行为是绝对不允许的
           
  • changes are made with pure functions

    (只能通过调用函数来改变状态)

    由于不能直接需改状态,ngrx/store 同时引入了一个叫做reducer(聚合器)的概念。通过reducer 来修改状态。

function reducer(state = 'SHOW_ALL', action) {
    switch (action.type) {
      	case 'SET_VISIBILITY_FILTER':
        	return Object.assign({}, newObj);  
        default:
        	return state  
        }
	}
           

ngrx/store使用实例

安装@ngrx/store

// 当前使用版本为6.1.2
npm install @ngrx/store or yarn add @ngrx/store
           

配置

创建

state

,

action

,

reducer

// counter.ts,一般需要将state,action,reducer进行文件拆分
import { Action } from '@ngrx/store';
export interface IAction extends Action {
    payload?: any; // dispatch数据载体,可有可无,继承Action的type属性
}

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const RESET = 'RESET';

const initialState = 0;

export function counterReducer(state: number = initialState, action: IAction) {
  switch (action.type) {
    case INCREMENT:
      return state + 1;

    case DECREMENT:
      return state - 1;

    case RESET:
      return 0;

    default:
      return state;
  }
}
           

注册store

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { counterReducer } from './counter';

@NgModule({
  imports: [
  	StoreModule.forRoot({ count: counterReducer }), // 注册store
  ],
})
export class AppModule {}
           

使用store

在组件或服务中注入store进行使用

// 组件级别
import { Component } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';
import { INCREMENT, DECREMENT, RESET } from './counter';

interface AppState {
  count: number;
}

@Component({
  selector: 'app-my-counter',
  template: `
    <button (click)="increment()">Increment</button>
    <div>Current Count: {{ count$ | async }}</div>
    <button (click)="decrement()">Decrement</button>

    <button (click)="reset()">Reset Counter</button>
  `,
})
export class MyCounterComponent {
  count$: Observable<number>;

  constructor(private store: Store<AppState>) { // 注入store
    this.count$ = store.pipe(select('count')); // 从app.module.ts中获取count状态流
  }

  increment() {
    this.store.dispatch({ type: INCREMENT });
  }

  decrement() {
    this.store.dispatch({ type: DECREMENT });
  }

  reset() {
    this.store.dispatch({ type: RESET });
  }
}
           

继续阅读