构建可扩展的状态系统:基于 ArkTS 的模块化状态管理设计与实现
摘要
在 HarmonyOS 的日常开发中,很多人都会遇到一个问题:多个页面之间的数据状态如何共享?尤其是在组件结构越来越复杂的场景下,如果还用传统方式来传值,不仅代码混乱,维护也很吃力。
为了解决这个问题,本文将介绍一种用 ArkTS 实现的“模块化状态管理”方式。它的思路有点类似于 React 中的 Redux,通过创建一个单独的状态模块,把所有共享状态集中管理,再在各个页面中引用它,从而实现状态同步更新。
引言
随着应用体量越来越大,一个页面一个状态的写法已经越来越难以满足业务需求了。例如:首页有一个计数器,设置页也需要读取和修改这个值;再比如,有些全局配置比如暗黑模式、用户登录信息等,全 app 都要用。
这种时候,模块化状态管理就非常有用了。它的好处是:
- 状态集中管理
- 页面之间不需要一层层传参
- 状态变化可控、可追踪
- 更易测试与维护
而 ArkTS 原生就支持单例和模块导入的机制,所以在 HarmonyOS 中实现模块化状态管理其实并不复杂。
用 ArkTS 实现模块化状态管理
创建一个状态模块(StateManager)
我们先来看一个最简单的状态管理模块,只包含一个全局的计数器:
// StateManager.ts
export class StateManager {private static instance: StateManager;public count: number = 0;private constructor() {}static getInstance() {if (!StateManager.instance) {StateManager.instance = new StateManager();}return StateManager.instance;}
}
这个模块用了经典的“单例模式”,也就是只创建一个实例,在整个 app 中共享。任何页面只要调用 StateManager.getInstance()
,就能拿到这个共享状态。
在页面中引用这个状态模块
下面我们写一个页面,展示这个 count 值,并且点击按钮让它 +1。
// MainPage.ets
import { StateManager } from './StateManager';@Entry
@Component
struct MainPage {private stateManager = StateManager.getInstance();build() {Column() {Text(`Count: ${this.stateManager.count}`).fontSize(20);Button('Increment').onClick(() => {this.stateManager.count++;});}.padding(20);}
}
现在我们打开这个页面,点击按钮,每点一次,count
就加一。
模块化状态在实际场景中的使用案例
案例 1:多页面共享的购物车数量
假设我们在商城 app 里有多个页面(比如首页、购物车页、商品详情页),都需要显示购物车里的商品数量。
状态模块
// CartState.ts
export class CartState {private static instance: CartState;public itemCount: number = 0;private constructor() {}static getInstance() {if (!CartState.instance) {CartState.instance = new CartState();}return CartState.instance;}addItem() {this.itemCount++;}clearCart() {this.itemCount = 0;}
}
首页展示购物车数量
// HomePage.ets
import { CartState } from './CartState';@Component
struct HomePage {private cartState = CartState.getInstance();build() {Row() {Text(`购物车商品数量: ${this.cartState.itemCount}`)Button('添加商品').onClick(() => {this.cartState.addItem();});}.padding(20);}
}
购物车页面清空功能
// CartPage.ets
import { CartState } from './CartState';@Component
struct CartPage {private cartState = CartState.getInstance();build() {Column() {Text(`当前数量: ${this.cartState.itemCount}`)Button('清空购物车').onClick(() => {this.cartState.clearCart();});}}
}
这样,两个页面共享同一个 CartState
实例,更新状态时,页面数据也会同步。
案例 2:全局用户信息管理
比如你有个用户模块,登录成功后需要把用户信息存下来,后续其他页面都能用。
// UserState.ts
export class UserState {private static instance: UserState;public username: string = '';public isLoggedIn: boolean = false;private constructor() {}static getInstance() {if (!UserState.instance) {UserState.instance = new UserState();}return UserState.instance;}login(name: string) {this.username = name;this.isLoggedIn = true;}logout() {this.username = '';this.isLoggedIn = false;}
}
你可以在登录页使用 login(name)
方法,在设置页调用 logout()
来退出登录,并在其他页面通过 isLoggedIn
来判断用户状态。
QA 环节:开发中常遇到的问题
Q1:这个状态会在页面切换后丢失吗?
不会。 因为用了单例模式,所以状态是保存在内存里的,除非应用被杀掉或者你主动清空。
Q2:多个组件同时引用这个状态,会冲突吗?
不会冲突,但不会自动刷新。 如果你在页面 A 修改了状态,页面 B 想实时感知,需要结合 @Observed
或自定义通知机制(比如事件总线)来实现响应式更新。
Q3:这个方式适合大型项目吗?
适合做轻量的状态管理。 如果项目非常复杂、状态特别多、需要响应式更新的场景比较多,建议结合 ArkTS 的 @Observed
, @State
, @Provide
等装饰器,或者结合事件总线、信号机制使用。
总结
模块化状态管理在 ArkTS 中是非常实用的一种方案,尤其适合开发多人协作或页面组件繁多的中大型项目。通过单例模式封装状态模块,我们可以实现:
- 页面之间的状态共享
- 状态统一管理,易于维护
- 代码结构清晰,易扩展
当然,如果你的应用场景对状态变化的实时性要求更高,推荐结合 ArkTS 的响应式装饰器或事件总线来做更进一步的扩展。
未来你也可以在这个基础上加上本地缓存(比如存入 Preferences
),或者结合 @Observed
属性做组件刷新。希望这篇文章能为你在 ArkTS 的开发旅程中提供一些思路和帮助!