Angular之store全局状态管理 浅学

在 Angular 应用中,我们可以使用 @ngrx/store 进行状态管理可以有效地管理和跟踪应用程序的状态变化。@ngrx/store 是基于 Redux 模式的状态管理库,它提供了一种集中式存储管理应用程序状态的方式。以下是关于 @ngrx/store 的详细解释和使用方法:

前言

@ngrx/store 提供了一种强大的机制来管理 Angular 应用程序的状态,使得应用程序的状态变化变得可预测和可追踪。通过定义 actions、reducers 和 selectors,并使用 select 函数来订阅状态变化,我们可以实现高效的状态管理,同时提高应用程序的可维护性和可测试性。同时,结合 Effects 可以处理复杂的异步逻辑,使得应用程序的状态管理更加完善和健壮。

1. 核心概念

1.1. Store

Store是整个应用程序状态的单一来源。它是一个 RxJS Observable,用于订阅状态的变化。通过 Store,我们可以获取、更新和订阅应用程序中的状态。

1.2. State

State 是应用程序的当前状态,通常表示为一个 JavaScript 对象。在 @ngrx/store 中,所有的状态都被组织成一个状态树,每个部分状态(或称为状态片段)都由一个 reducer 函数管理。

1.3. Actions

Actions 是一个描述状态变化的简单对象,它包含了一个 type属性和可选的playload属性。通过 dispatching actions,我们可以触发状态的变化。

1.4. Reducers

Reducers是纯函数,它接收当前状态和一个 action,并返回新的状态。Reducers 用于处理不同类型的 actions,更新相应的部分状态。

2. 安装和配置 @ngrx/store

2.1. 安装 @ngrx/store
javascript 复制代码
npm install @ngrx/store --save
2.2. 在 Angular 应用中配置 StoreModule

在 Angular 的根模块(通常是 AppModule)中导入 StoreModule.forRoot(),并传入一个包含所有 reducers 的对象。

javascript 复制代码
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './reducers'; // 导入应用程序的 reducers

@NgModule({
  imports: [
    BrowserModule,
    StoreModule.forRoot(reducers, {
      metaReducers,
      runtimeChecks: {
        strictStateImmutability: true,
        strictActionImmutability: true,
      }
    })
  ],
  declarations: [],
  bootstrap: []
})
export class AppModule { }
  • reducers是一个对象,包含了应用程序的所有 reducer 函数。
  • metaReducers是一些处理 reducer 的高阶函数,例如日志记录、状态恢复等。
  • runtimeChecks是一个可选配置对象,用于开启严格的状态和 action 不可变性检查。

3. 创建和使用 Actions、Reducers 和 State

3.1. 定义 Actions
javascript 复制代码
// user.actions.ts
import { createAction, props } from '@ngrx/store';
import { User } from './user.model';

export const setUser = createAction('[User] Set User', props<{ user: User }>());

export const clearUser = createAction('[User] Clear User');
3.2. 创建 Reducers
javascript 复制代码
// user.reducer.ts
import { Action, createReducer, on } from '@ngrx/store';
import { User } from './user.model';
import * as UserActions from './user.actions';

export interface UserState {
  user: User | null;
}

export const initialState: UserState = {
  user: null,
};

const userReducer = createReducer(
  initialState,
  on(UserActions.setUser, (state, { user }) => ({ ...state, user })),
  on(UserActions.clearUser, (state) => ({ ...state, user: null })),
);

export function reducer(state: UserState | undefined, action: Action) {
  return userReducer(state, action);
}
3.3. 使用 State 和 Dispatch Actions
javascript 复制代码
// user.component.ts
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from './app.state'; // 应用状态的类型定义
import { setUser, clearUser } from './store/user/user.actions'; // Actions 的导入

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent {

  constructor(private store: Store<AppState>) { }

  setUser(): void {
    const user = { id: '1', name: 'John Doe', email: 'john.doe@example.com' };
    this.store.dispatch(setUser({ user }));
  }

  clearUser(): void {
    this.store.dispatch(clearUser());
  }

}

4. 在组件中使用 select 函数获取状态

4.1. 定义选择器函数
javascript 复制代码
// user.selector.ts
import { createSelector, createFeatureSelector } from '@ngrx/store';
import { AppState } from '../../app.state'; // 应用状态的类型定义
import { UserState } from './user.reducer'; // 用户状态的类型定义

// 创建特性选择器,用于选择用户状态
export const selectUserState = createFeatureSelector<AppState, UserState>('user');

// 创建选择器函数,用于选择用户信息
export const getUser = createSelector(
  selectUserState,
  (state: UserState) => state.user
);
4.2. 在组件中使用 select 函数订阅状态
javascript 复制代码
// user.component.ts
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import { AppState } from './app.state'; // 应用状态的类型定义
import { Observable } from 'rxjs';
import { getUser } from './store/user/user.selector'; // 选择器函数的导入
import { User } from './store/user/user.model'; // 用户模型的导入

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  user$: Observable<User>; // 声明一个可观察对象,用来订阅用户状态

  constructor(private store: Store<AppState>) { }

  ngOnInit(): void {
    this.user$ = this.store.pipe(select(getUser)); // 使用 select 函数选择用户状态
  }
}
4.3. 在模板中使用 Async 管道订阅状态
javascript 复制代码
<!-- user.component.html -->
<div *ngIf="user$ | async as user">
  <p>User Name: {{ user.name }}</p>
  <p>User Email: {{ user.email }}</p>
</div>

5. 异步状态管理

对于异步操作(如 HTTP 请求),可以使用 Effects,它允许我们在响应 action 时执行副作用,并将结果作为新的 action 分发到 store 中。这样可以保持 reducer 函数的纯粹性。

6. forFeature方法

@ngrx/store 中,forFeature 方法是用来在特性模块中注册和配置状态的一种重要方式。特性模块可以理解为应用程序中的一个子模块,它可能包含了相关的业务逻辑、状态管理和视图组件。使用 forFeature 可以使得特性模块中的状态管理更加模块化和独立,同时能够与全局状态进行合理的整合。

使用场景和示例
1. 在特性模块中注册状态

假设我们有一个应用程序,其中有一个特性模块管理用户信息的状态。我们可以使用 forFeature 来注册并配置该特性模块的状态。

javascript 复制代码
// user.reducer.ts
import { Action, createReducer, on } from '@ngrx/store';
import { User } from './user.model';
import * as UserActions from './user.actions';

export interface UserState {
  user: User | null;
}

export const initialState: UserState = {
  user: null,
};

const userReducer = createReducer(
  initialState,
  on(UserActions.setUser, (state, { user }) => ({ ...state, user })),
  on(UserActions.clearUser, (state) => ({ ...state, user: null })),
);

export function reducer(state: UserState | undefined, action: Action) {
  return userReducer(state, action);
}
2. 在特性模块中使用 forFeature

在特性模块中,我们需要导入 StoreModule 和相应的 reducer 函数,并使用 forFeature 来注册该特性模块的状态。

javascript 复制代码
// user.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { StoreModule } from '@ngrx/store';
import { reducer } from './user.reducer'; // 导入用户特性模块的 reducer

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    StoreModule.forFeature('user', reducer), // 使用 forFeature 注册用户特性模块的状态
  ],
})
export class UserModule { }
详细解释
Reducer 定义

user.reducer.ts 中定义了一个用户特性模块的 reducer 函数,它负责管理用户信息的状态变化。这里的 initialState 定义了初始的状态对象,userReducer 使用 createReducer 函数来处理不同类型的 action,并更新相应的状态。
2. 特性模块中的 StoreModule.forFeature

UserModule 中,我们使用 StoreModule.forFeature 方法来注册用户特性模块的状态。forFeature 方法接收两个参数:

  • 第一个参数是一个字符串,用来标识注册的状态在全局状态树中的位置。在这里我们使用 user,表示用户特性模块的状态将会存储在全局状态树的 user 键下。
  • 第二个参数是特性模块的 reducer 函数,用来管理特性模块中的状态变化。
  1. 在应用中使用特性模块

    在主模块或其他需要使用用户特性模块的地方,只需导入 UserModule,Angular 就会自动注册和配置该模块的状态。

javascript 复制代码
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './reducers'; // 导入应用程序的 reducers
import { UserModule } from './user/user.module'; // 导入用户特性模块

@NgModule({
  imports: [
    BrowserModule,
    StoreModule.forRoot(reducers, { metaReducers }),
    UserModule, // 导入并使用用户特性模块
  ],
  declarations: [],
  bootstrap: []
})
export class AppModule { }
优势和适用场景
  • 模块化 :使用 forFeature 可以使得状态管理更加模块化,每个特性模块可以独立管理自己的状态和逻辑,提高了代码的可维护性和可重用性。
  • 分割状态:通过注册不同的特性模块,可以将全局状态树分割为多个小块,使得状态管理更加清晰和灵活。
  • 依赖注入:Angular 的依赖注入机制能够有效地管理特性模块的依赖关系,使得状态的使用和管理更加一致和可控。

参考博文

https://blog.51cto.com/devpoint/4925185

Angular Ngrx 里 Store 和 State 的关系-阿里云开发者社区

相关推荐
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端
程序猿阿伟3 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒3 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪3 小时前
AJAX的基本使用
前端·javascript·ajax