一文快速了解Angular中的NgRx/Store框架


本文摘自PHP中文网,作者青灯夜游,侵删。

Angular中什么是NgRx/Store框架?有什么用?本篇文章就来带大家了解一下NgRx/Store数据状态管理框架,ngrx/store中的基本原则,通过示例了解一下该框架的简单用法。

【相关教程推荐:《angular教程》】

ngrx/store 是基于RxJS的状态管理库,其灵感来源于Redux。在NgRx中,状态是由一个包含actionreducer的函数的映射组成的。Reducer函数经由action的分发以及当前或初始的状态而被调用,最后由reducer返回一个不可变的状态。

1.gif

状态管理

在前端大型复杂Angular/AngularJS项目的状态管理一直是个让人头疼的问题。在AngularJS(1.x版本)中,状态管理通常由服务,事件,$rootScope混合处理。在Angular中(2+版本),组件通信让状态管理变得清晰一些,但还是有点复杂,根据数据流向不同会用到很多方法。

ngrx/store中的基本原则

视图层通过dispatch发起一个行为(action)、Reducer接收action,根据action.type类型来判断执行、改变状态、返回一个新的状态给store、由store更新state

2.gif

  • State(状态) 是状态(state)存储器
  • Action(行为) 描述状态的变化
  • Reducer(归约器/归约函数) 根据先前状态以及当前行为来计算出新的状态,里面的方法为纯函数
  • 状态用State的可观察对象,Action的观察者――Store来访问

Actions(行为)

Actions是信息的载体,它发送数据到reducer,然后reducer更新storeActionsstore能接受数据的唯一方式。

ngrx/store里,Action的接口是这样的:

1

2

3

4

5

// actions包括行为类型和对应的数据载体

export interface Action {

  type: string;

  payload?: any;

}

type描述期待的状态变化类型。比如,添加待办 ADD_TODO,增加 DECREMENT 等。payload是发送到待更新store中的数据。store派发action 的代码类似如下:

1

2

3

4

5

// 派发action,从而更新store

store.dispatch({

  type: 'ADD_TODO',

  payload: 'Buy milk'

});

Reducers(归约器)

Reducers规定了行为对应的具体状态变化。是纯函数,通过接收前一个状态和派发行为返回新对象作为下一个状态的方式来改变状态,新对象通常用Object.assign和扩展语法来实现。

1

2

3

4

5

6

7

8

9

// reducer定义了action被派发时state的具体改变方式

export const todoReducer = (state = [], action) => {

  switch(action.type) {

    case 'ADD_TODO':

      return [...state, action.payload];

    default:

      return state;

  }

}

开发时特别要注意函数的纯性。因为纯函数:

  • 不会改变它作用域外的状态
  • 输出只决定于输入
  • 相同输入,总是得到相同输出

Store(存储)

store中储存了应用中所有的不可变状态。ngrx/store中的storeRxJS状态的可观察对象,以及行为的观察者。

可以利用Store来派发行为。也可以用Store的select()方法获取可观察对象,然后订阅观察,在状态变化之后做出反应。

上面我们描述的是基本流程。在实际开发过程中,会涉及API请求、浏览器存储等异步操作,就需要effectsserviceseffectsaction触发,进行一些列逻辑后发出一个或者多个需要添加到队列的action,再由reducers处理。

3.gif

使用ngrx/store框架开发应用,始终只维护一个状态,并减少对API的调用。

简单示例

简单介绍一个管理系统的登录模块。

创建Form表单

1、增加组件:LoginComponent,主要就是布局,代码为组件逻辑

2、定义用户:User Model

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

export class User {

    id: number;

    username: string;

    password: string;

    email: string;

    avatar: string;

 

    clear(): void {

        this.id = undefined;

        this.username = "";

        this.password = "";

        this.email = "";

        this.avatar = "./assets/default.jpg";

    }

}

3、添加表单:在组件LoginComponent增加Form表单

NGRX Store

按照上述的4个原则定义相应的Actions

4.gif

  • reducers定义状态

    在文件auth.reducers.ts中创建状态,并初始化

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    export interface AuthState {

        isAuthenticated: boolean;

        user: User | null;

        errorMessage: string | null;

    }

     

    export const initialAuthState: AuthState = {

        isAuthenticated: false,

        user: null,

        errorMessage: null

    };

  • actions定义行为

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    export enum AuthActionTypes {

        Login = "[Auth] Login",

        LoginSuccess = "[Auth] Login Success",

        LoginFailure = "[Auth] Login Failure"

    }

     

    export class Login implements Action {

        readonly type = AuthActionTypes.Login;

        constructor(public payload: any) {}

    }

  • service实现数据交互(服务器)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    @Injectable()

    export class AuthService {

        private BASE_URL = "api/user";

     

        constructor(private http: HttpClient) {}

     

        getToken(): string {

            return localStorage.getItem("token");

        }

     

        login(email: string, pwd: string): Observable<any> {

            const url = `${this.BASE_URL}/login`;

            return this.http.post<User>(url, { email, pwd });

        }

    }

  • effects侦听从Store调度的动作,执行某些逻辑,然后分派新动作

    • 一般情况下只在这里调用API

    • 通过返回一个action给reducer进行操作来改变store的状态

    • effects总是返回一个或多个action(除非@Effect with {dispatch: false})

5.gif

  • 1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    @Effect()

    Login: Observable<any> = this.actions.pipe(

        ofType(AuthActionTypes.Login),   //执行Login响应

        map((action: Login) => action.payload),

        switchMap(payload => {

            return this.authService.login(payload.email, payload.password).pipe(

                map(user => {

                    return new LoginSuccess({ uid: user.id, email: payload.email });

                }),

                catchError(error => {

                    return of(new LoginFailure(error));

                })

            );

        })

    );

     

    //失败的效果

    @Effect({ dispatch: false })

    LoginFailure: Observable<any> = this.actions.pipe(ofType(AuthActionTypes.LoginFailure));

     

    //成功的效果

    @Effect({ dispatch: false })

    LoginSuccess: Observable<any> = this.actions.pipe(

        ofType(AuthActionTypes.LoginSuccess),

        tap(user => {

            localStorage.setItem("uid", user.payload.id);

            this.router.navigateByUrl("/sample");

        })

    );

更多编程相关知识,请访问:编程视频!!

以上就是一文快速了解Angular中的NgRx/Store框架的详细内容,更多文章请关注木庄网络博客

相关阅读 >>

vuetify是什么框架?

浅析Angular路由中的懒加载、守卫、动态参数

了解一下Angular中的@input()和@output()

浅谈Angular如何编译打包?如何使用docker发布?

深入了解Angular中的component组件

深入了解Angular中的hostbinding和hostlistener装饰器

Angular组件怎么进行通信?父子组件通信的2种方法

深入了解Angular组件中的生命周期钩子

浅谈Angular中插槽的用法

浅谈Angular如何使用ng-content进行内容投影

更多相关阅读请进入《Angular》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...