NGXS状态管理核心概念:State详解

NGXS状态管理核心概念:State详解

store 🚀 NGXS - State Management for Angular store 项目地址: https://gitcode.com/gh_mirrors/sto/store

什么是State

在NGXS状态管理库中,State(状态)是应用数据存储的核心容器。它类似于Redux中的reducer,但采用了更现代化的实现方式,通过装饰器和类来定义状态容器及其行为。

状态定义基础

定义一个状态容器非常简单,只需要创建一个类并使用@State装饰器:

import { Injectable } from '@angular/core';
import { State } from '@ngxs/store';

@State<string[]>({
  name: 'animals',
  defaults: []
})
@Injectable()
export class AnimalsState {}

@State装饰器接收一个配置对象,其中包含三个关键属性:

  1. name:状态的唯一标识符,必须是有效的对象属性名
  2. defaults:状态的初始值
  3. children(已废弃):子状态关联,新项目不建议使用

状态依赖注入

NGXS状态容器完全支持Angular的依赖注入系统,这使得我们可以在状态类中注入所需的服务:

@State<ZooStateModel>({
  name: 'zoo',
  defaults: {
    feed: false
  }
})
@Injectable()
export class ZooState {
  constructor(private zooService: ZooService) {}
}

使用StateToken定义状态

为了更好的类型安全和重构能力,NGXS提供了StateToken来替代直接使用字符串名称:

const ZOO_STATE_TOKEN = new StateToken<ZooStateModel>('zoo');

@State({
  name: ZOO_STATE_TOKEN,
  defaults: {
    feed: false
  }
})
@Injectable()
export class ZooState {}

这种方式在大型项目中特别有用,可以避免硬编码字符串带来的维护问题。

状态操作:Action处理

状态通过@Action装饰器来响应各种操作。Action是NGXS中改变状态的唯一方式。

基础Action处理

@Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>) {
  const state = ctx.getState();
  ctx.setState({
    ...state,
    feed: !state.feed
  });
}

StateContext提供了几个关键方法:

  • getState():获取当前状态(总是返回最新值)
  • setState():设置新状态
  • patchState():部分更新状态

带参数的Action

@Action(FeedZebra)
feedZebra(ctx: StateContext<ZooStateModel>, action: FeedZebra) {
  const state = ctx.getState();
  ctx.patchState({
    zebraFood: [...state.zebraFood, action.zebraToFeed]
  });
}

patchStatesetState的简化版,特别适合部分状态更新。

状态更新方式对比

NGXS提供了两种状态更新方式:

  1. 直接提供新状态对象:
ctx.setState({ ...ctx.getState(), value: payload });
  1. 使用函数返回新状态:
ctx.setState((state) => ({ ...state, value: payload }));

第二种方式更利于使用状态操作符和实现更声明式的代码。

高级状态更新技巧

使用Immer简化不可变更新

import produce from 'immer';

@Action(FeedZebra)
feedZebra(ctx: StateContext<ZooStateModel>, action: FeedZebra) {
  ctx.setState(produce((draft) => {
    draft.zebraFood.push(action.zebraToFeed);
  }));
}

Immer库允许我们以可变的方式编写代码,但实际上执行的是不可变更新。

创建可复用的状态更新函数

function addToZebraFood(itemToAdd) {
  return produce((draft) => {
    draft.zebraFood.push(itemToAdd);
  });
}

@Action(FeedZebra)
feedZebra(ctx: StateContext<ZooStateModel>, action: FeedZebra) {
  ctx.setState(addToZebraFood(action.zebraToFeed));
}

这种方式可以大大提高代码的复用性和可维护性。

异步操作处理

NGXS完美支持异步操作,无需额外中间件。

使用Observable

@Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
  return this.animalService.feed(action.animalsToFeed).pipe(
    tap(animalsToFeedResult => {
      ctx.patchState({
        feedAnimals: [...ctx.getState().feedAnimals, animalsToFeedResult]
      });
    })
  );
}

使用async/await

@Action(FeedAnimals)
async feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
  const result = await this.animalService.feed(action.animalsToFeed);
  ctx.patchState({
    feedAnimals: [...ctx.getState().feedAnimals, result]
  });
}

Action间的级联调用

在一个Action处理完成后,可以继续派发其他Action:

@Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
  const state = ctx.getState();
  ctx.patchState({
    feedAnimals: [...state.feedAnimals, action.animalsToFeed]
  });
  return ctx.dispatch(new TakeAnimalsOutside());
}

对于异步操作:

@Action(FeedAnimals)
feedAnimals2(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
  return this.animalService.feed(action.animalsToFeed).pipe(
    tap(result => ctx.patchState({ feedAnimals: result })),
    mergeMap(() => ctx.dispatch(new TakeAnimalsOutside()))
  );
}

总结

NGXS的State概念提供了一种强大而灵活的方式来管理应用状态。通过类+装饰器的组合,我们能够:

  1. 清晰地定义状态结构和初始值
  2. 通过Action响应各种状态变更
  3. 处理同步和异步操作
  4. 实现Action间的级联调用
  5. 使用各种技巧简化不可变更新

这些特性使得NGXS成为Angular应用中状态管理的优秀选择,既保持了Redux的核心思想,又提供了更符合Angular习惯的开发体验。

store 🚀 NGXS - State Management for Angular store 项目地址: https://gitcode.com/gh_mirrors/sto/store

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶名战Blanche

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值