直接跳到内容

Angular 状态管理

状态管理概念

状态管理是管理应用数据 (状态) 和状态变化的系统化方法,确保数据在组件之间保持一致性和可预测性。

示意图:

应用状态组成:
┌─────────────────┐
│   全局状态       │ ← 多个组件共享
│  - 用户信息      │
│  - 应用配置      │
│  - 缓存数据      │
└─────────────────┘
┌─────────────────┐
│   局部状态       │ ← 单个组件私有
│  - 表单数据      │
│  - UI状态        │
│  - 加载状态      │
└─────────────────┘

状态管理挑战

组件通信问题

在大型应用中,组件间状态共享变得复杂。

示意图:

状态传递困境:
    组件A (有状态)
       ↓ props
    组件B 
       ↓ props  
    组件C (需要状态)
       ↑ props
    组件D (修改状态)

问题:多层传递、难以维护、状态分散

状态分散问题

状态逻辑分散在不同组件中,导致不一致性。

示意图:

状态分散:
┌─────────┐  ┌─────────┐  ┌─────────┐
│ 组件A    │  │ 组件B    │  │ 组件C    │
│ 状态副本  │  │ 状态副本  │  │ 状态副本  │
└─────────┘  └─────────┘  └─────────┘
    各自维护,可能不一致

服务状态管理

基础服务模式

使用 Angular 服务作为单一数据源管理状态。

示意图:

服务状态中心:
        ┌─────────────┐
        │  状态服务    │ ← 单一数据源
        │  ┌─────────┐ │
        │  │ 状态对象  │ │
        │  └─────────┘ │
        └─────────────┘
           /    |    \
          /     |     \
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 组件A    │ │ 组件B    │ │ 组件C    │
│ 读取状态 │ │ 更新状态 │ │ 监听变化 │
└─────────┘ └─────────┘ └─────────┘

可观察状态模式

使用 RxJS BehaviorSubject 实现响应式状态管理。

示意图:

响应式状态流:
状态服务 → BehaviorSubject → 组件订阅

数据流:
状态更新 → next(value) → 订阅者接收新值

实现示例:

typescript
@Injectable({ providedIn: 'root' })
export class UserStateService {
  private userSubject = new BehaviorSubject<User | null>(null);
  public user$ = this.userSubject.asObservable();
  
  setUser(user: User): void {
    this.userSubject.next(user);
  }
}

RxJS 状态管理

状态流模式

使用 RxJS 操作符管理复杂状态流。

示意图:

状态操作链:
数据源 → 转换 → 过滤 → 组合 → 状态输出

示例:
userData$ → map(transform) → filter(activeOnly) → combineLatest(profile$) → 最终状态

状态组合

组合多个状态流创建衍生状态。

示意图:

状态组合:
┌─────────┐   ┌─────────┐
│ 状态A$   │   │ 状态B$   │
└─────────┘   └─────────┘
       \         /
        \       /
      combineLatest
           |

      ┌─────────┐
      │ 组合状态  │
      └─────────┘

NgRx 状态管理

Redux 模式

NgRx 实现 Redux 模式:单一数据源、状态只读、纯函数更新。

示意图:

Redux 数据流:
     Action 

    Reducer (纯函数)

     Store (单一状态树)

    Selectors (状态选择)

    Components (组件)

核心概念

NgRx 架构的核心组成部分。

示意图:

NgRx 结构:
┌─────────────────┐
│    Actions      │ ← 描述状态变化
│  - 类型         │
│  - 载荷         │
├─────────────────┤
│    Reducers     │ ← 纯函数处理状态
│  - 当前状态      │
│  - Action       │
│  - 新状态        │
├─────────────────┤
│    Store        │ ← 状态容器
│  - 状态树        │
│  - 派发Actions   │
├─────────────────┤
│   Selectors     │ ← 状态查询
│  - 状态派生      │
│  - 记忆化计算    │
└─────────────────┘

数据流详细流程

完整的 NgRx 状态更新周期。

示意图:

NgRx 数据流:
组件 → Action → Reducer → Store → Selector → 组件更新

详细步骤:
1. 组件 dispatch(Action)
2. Action 触发 Reducer
3. Reducer 返回新状态
4. Store 更新状态
5. Selector 通知订阅者
6. 组件接收新状态

组件本地状态

本地状态管理

使用组件内状态管理本地 UI 状态。

示意图:

组件内部状态:
┌─────────────────┐
│   组件类         │
│  ┌─────────────┐ │
│  │ 本地状态     │ │
│  │ - loading   │ │
│  │ - formData  │ │
│  │ - isOpen    │ │
│  └─────────────┘ │
└─────────────────┘

智能与展示组件

分离状态逻辑和 UI 展示的组件设计模式。

示意图:

组件分离:
┌─────────────────┐    @Input()    ┌─────────────────┐
│  智能组件        │ ─────────────> │  展示组件        │
│  - 管理状态      │               │  - 纯UI展示      │
│  - 处理业务逻辑  │ <───────────── │  - 无状态        │
│  - 数据获取      │   @Output()   │  - 事件发射      │
└─────────────────┘               └─────────────────┘

状态持久化

本地存储集成

将状态持久化到浏览器存储中。

示意图:

状态持久化:
应用状态 → 序列化 → localStorage → 反序列化 → 恢复状态

流程:
状态变化 → 自动保存 → 页面刷新 → 自动恢复

路由状态管理

使用路由参数管理页面级状态。

示意图:

路由状态:
URL参数 → 路由解析 → 组件状态

示例:
/products?category=electronics&page=2

组件读取路由参数初始化状态

状态管理策略选择

方案对比

不同状态管理方案的适用场景。

示意图:

方案选择指南:
┌──────────────┬──────────────┬──────────────┐
│   方案        │ 适用场景      │ 复杂度        │
├──────────────┼──────────────┼──────────────┤
│ 服务 + Subject │ 中小型应用    │ 低           │
│ 服务 + RxJS   │ 中大型应用    │ 中           │
│ NgRx         │ 大型复杂应用  │ 高           │
└──────────────┴──────────────┴──────────────┘

混合策略

根据应用不同部分使用不同的状态管理方式。

示意图:

混合策略:
        ┌─────────────┐
        │  全局状态    │ ← NgRx (复杂业务)
        └─────────────┘
        ┌─────────────┐
        │  功能状态    │ ← RxJS服务 (中等复杂度)
        └─────────────┘
        ┌─────────────┐
        │  UI状态      │ ← 组件本地状态 (简单)
        └─────────────┘

状态调试与工具

开发工具

使用 Redux DevTools 进行状态调试。

示意图:

调试流程:
状态变化 → 动作记录 → 时间旅行调试

工具功能:
- 查看状态历史
- 重放动作
- 状态快照比较

不可变更新模式

使用不可变数据确保状态更新的可预测性。

示意图:

不可变更新:
原始状态 → 创建副本 → 修改副本 → 新状态

正确做法:
return { ...state, user: action.user }

错误做法:
state.user = action.user // 直接修改
return state

最佳实践

状态规范化

规范化状态结构,避免数据冗余和嵌套。

示意图:

状态结构对比:
非规范化:               规范化:
{                      {
  posts: [               posts: { 
    { id:1, user: {..}},   byId: { 1: {..}, 2: {..} },
    { id:2, user: {..}}    allIds: [1, 2]
  ]                     },
}                       users: { ... }

副作用管理

使用 Effects 或 RxJS 管理异步操作和副作用。

示意图:

副作用处理:
Action → Effect → 异步操作 → 新Action → Reducer

示例:
LoadUsers → API调用 → LoadUsersSuccess → 更新状态
Angular 状态管理已经加载完毕