
摘要
在 HarmonyOS 的日常开发中,很多人都会遇到一个问题:多个页面之间的数据状态如何共享?尤其是在组件结构越来越复杂的场景下,如果还用传统方式来传值,不仅代码混乱,维护也很吃力。
为了解决这个问题,本文将介绍一种用 ArkTS 实现的"模块化状态管理"方式。它的思路有点类似于 React 中的 Redux,通过创建一个单独的状态模块,把所有共享状态集中管理,再在各个页面中引用它,从而实现状态同步更新。
引言
随着应用体量越来越大,一个页面一个状态的写法已经越来越难以满足业务需求了。例如:首页有一个计数器,设置页也需要读取和修改这个值;再比如,有些全局配置比如暗黑模式、用户登录信息等,全 app 都要用。
这种时候,模块化状态管理就非常有用了。它的好处是:
- 状态集中管理
- 页面之间不需要一层层传参
- 状态变化可控、可追踪
- 更易测试与维护
而 ArkTS 原生就支持单例和模块导入的机制,所以在 HarmonyOS 中实现模块化状态管理其实并不复杂。
用 ArkTS 实现模块化状态管理
创建一个状态模块(StateManager)
我们先来看一个最简单的状态管理模块,只包含一个全局的计数器:
ts
// 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。
ts
// 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 里有多个页面(比如首页、购物车页、商品详情页),都需要显示购物车里的商品数量。
状态模块
ts
// 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;
}
}
首页展示购物车数量
ts
// 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);
}
}
购物车页面清空功能
ts
// 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:全局用户信息管理
比如你有个用户模块,登录成功后需要把用户信息存下来,后续其他页面都能用。
ts
// 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 的开发旅程中提供一些思路和帮助!