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 的关系-阿里云开发者社区

相关推荐
passerby606143 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte3 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc