文章目录
鸿蒙开发状态管理与工程化通俗解释及案例
状态管理通俗解释
核心概念类比
组件状态管理
- @State:组件的"内部记忆",就像个人笔记本,记录组件自己的状态,修改时会自动更新UI
- @Prop:“单向传递的消息”,从父组件传到子组件,子组件可以读取但不能修改
- @Link:“双向对讲机”,父子组件都能修改并同步更新,适合需要共同操作的数据
- @Provide/@Consume:“家庭广播系统”,跨层级传递信息,无需逐层传递
全局状态管理
- AppStorage:“社区公告栏”,整个应用都能访问的公共信息板
- LocalStorage:“房间白板”,仅限当前页面(UIAbility)内的组件共享
- PersistentStorage:“永久日记本”,应用重启后依然保留的重要信息
V1 vs V2版本对比
特性 | V1版本 | V2版本 | 通俗理解 |
---|---|---|---|
观察能力 | 仅支持单层对象观察 | 支持深度嵌套对象观察 | V1只能看到盒子表面,V2能看到盒子里的每个物品 |
更新粒度 | 组件级更新 | 属性级精准更新 | V1更新整个房间,V2只更新变化的物品 |
状态独立性 | 依赖UI组件 | 独立于UI存在 | V1状态必须放在展示柜里,V2状态可以单独存放 |
实际开发案例
案例1:购物车计数器(基础状态管理)
场景:用户点击"+"按钮增加购物车商品数量,UI实时更新
@Entry @Component
struct ShoppingCartCounter {
// 声明购物车商品数量状态变量
@State quantity: number = 0;
build() {
Column() {
// 显示当前数量
Text(`购物车商品: ${this.quantity}件`)
.fontSize(20)
.margin(10)
// 增加按钮
Button("+")
.fontSize(20)
.width(50)
.height(50)
.onClick(() => {
// 修改状态变量,自动触发UI更新
this.quantity++;
})
// 减少按钮
Button("-")
.fontSize(20)
.width(50)
.height(50)
.onClick(() => {
if (this.quantity > 0) {
this.quantity--;
}
})
}
}
}
工作原理:
@State
装饰的quantity
变量是组件的"记忆"- 点击按钮修改
quantity
时,系统自动检测变化 - 触发UI重新渲染,显示最新数量
案例2:用户登录状态共享(全局状态管理)
场景:用户登录后,多个页面需要显示用户信息
// 1. 应用启动时初始化全局状态
PersistentStorage.persistProp('isLoggedIn', false);
PersistentStorage.persistProp('username', '');
// 2. 登录页面 - 修改全局状态
@Component
struct LoginPage {
@StorageLink('isLoggedIn') isLoggedIn: boolean = false;
@StorageLink('username') username: string = '';
@State inputUsername: string = '';
build() {
Column() {
TextInput({ placeholder: '请输入用户名' })
.onChange((value) => this.inputUsername = value)
Button('登录')
.onClick(() => {
this.isLoggedIn = true;
this.username = this.inputUsername;
// 跳转到首页
router.pushUrl({ url: 'pages/HomePage' });
})
}
}
}
// 3. 首页 - 读取全局状态
@Component
struct HomePage {
@StorageProp('isLoggedIn') isLoggedIn: boolean = false;
@StorageProp('username') username: string = '';
build() {
Column() {
if (this.isLoggedIn) {
Text(`欢迎回来,${this.username}!`)
} else {
Text('请先登录')
}
}
}
}
工作原理:
PersistentStorage
保存用户登录状态,应用重启后依然保留@StorageLink
实现双向绑定,登录页面修改后全局生效- 其他页面通过
@StorageProp
读取登录状态,实现跨页面共享
案例3:待办事项应用(工程化实践)
场景:实现一个支持添加、标记完成、删除的待办事项应用,采用模块化设计
// 1. 数据模型(models/TodoItem.ets)
@ObservedV2
export class TodoItem {
@Trace id: number;
@Trace content: string;
@Trace isCompleted: boolean;
constructor(id: number, content: string) {
this.id = id;
this.content = content;
this.isCompleted = false;
}
}
// 2. 状态管理(viewmodels/TodoViewModel.ets)
export class TodoViewModel {
@ObservedV2 items: TodoItem[] = [];
private nextId: number = 1;
addTodo(content: string) {
if (content.trim()) {
this.items.push(new TodoItem(this.nextId++, content));
}
}
toggleComplete(id: number) {
const item = this.items.find(item => item.id === id);
if (item) {
item.isCompleted = !item.isCompleted;
}
}
deleteTodo(id: number) {
this.items = this.items.filter(item => item.id !== id);
}
}
// 3. UI组件(components/TodoList.ets)
@Component
export struct TodoList {
@Prop viewModel: TodoViewModel;
build() {
List() {
ForEach(this.viewModel.items, (item) => {
ListItem() {
Row() {
Checkbox()
.checked(item.isCompleted)
.onChange(() => this.viewModel.toggleComplete(item.id))
Text(item.content)
.decoration({
type: item.isCompleted ? TextDecorationType.LineThrough : TextDecorationType.None
})
Blank()
Button('删除')
.onClick(() => this.viewModel.deleteTodo(item.id))
}
.padding(10)
}
})
}
}
}
// 4. 页面组装(pages/TodoPage.ets)
@Entry
@Component
struct TodoPage {
private viewModel: TodoViewModel = new TodoViewModel();
@State newTodoContent: string = '';
build() {
Column() {
TextInput({ placeholder: '输入新的待办事项' })
.onChange((value) => this.newTodoContent = value)
Button('添加')
.onClick(() => {
this.viewModel.addTodo(this.newTodoContent);
this.newTodoContent = '';
})
TodoList({ viewModel: this.viewModel })
}
.padding(10)
}
}
工程化亮点:
- 分层架构:数据模型、状态管理、UI组件分离
- 模块化设计:各功能独立封装,便于维护和复用
- 响应式更新:使用V2版本装饰器实现精准UI更新
- 单一数据源:通过ViewModel集中管理状态逻辑
鸿蒙开发状态管理与工程化关键信息汇总
状态管理核心概念
V1版本装饰器
- @State:组件内部状态变量,值变化触发UI刷新
- @Prop:父子组件单向数据同步
- @Link:父子组件双向数据绑定
- @Provide/@Consume:跨组件层级状态共享
- @Observed:用于观察多层嵌套对象的变化
V2版本增强特性
- 深度观察:支持对象的深度观测和监听
- 属性级更新:支持对象属性级精准更新及数组元素最小化更新
- 新装饰器:@ObservedV2、@Trace、@Local、@Param、@Once、@Event、@Monitor等
- 状态独立:状态变量独立于UI,更改数据触发相应视图更新
全局状态管理方案
- AppStorage:应用级UI状态存储,与进程绑定
- LocalStorage:页面级UI状态存储,通常用于UIAbility内状态共享
- PersistentStorage:持久化存储UI状态,确保应用重启后状态恢复
- StateStore:状态与UI解耦的全局状态管理方案,支持子线程更新
工程化实践
DevOps全流程自动化
-
开发自动化:
- Git代码托管与协作
- 智能编译与依赖管理
- 代码规范自动校验
-
测试自动化:
- 单元测试框架(@ohos.test)
- UI自动化测试(HTest)
- 测试用例示例:
// 商品详情页价格计算逻辑测试 import test from '@ohos.test'; import { calculatePrice } from '../utils/PriceUtils'; @test.function export function testCalculatePrice() { // 测试正常情况 let result = calculatePrice(199, 0.8); // 原价199,折扣0.8 test.assertEqual(result, 159.2, '折扣计算错误'); // 测试边界情况(满减) result = calculatePrice(299, 1, 50); // 满299减50 test.assertEqual(result, 249, '满减计算错误'); }
-
发布自动化:
- 原子化服务自动打包签名
- 自动上传与审核流程
- 多渠道分发管理
模块化架构设计
三层工程结构
- common(公共能力层):
- 工具类库
- 公共配置
- 编译为HAR包
- features(基础特性层):
- 业务功能模块
- 可独立部署为Feature HAP
- 或编译为HAR/HSP包
- products(产品定制层):
- 设备个性化实现
- 多端适配配置
- 编译为Entry HAP
模块类型选择指南
包类型 | 部署方式 | 功能特性 | 典型应用场景 |
---|---|---|---|
Entry | 独立部署 | 包含UI和设备定制逻辑 | 各设备主入口模块 |
Feature | 独立部署 | 可独立运行的特性模块 | 可动态加载的功能插件 |
HAR | 作为依赖引用 | 静态共享功能 | 公共组件库、工具类 |
HSP | 作为依赖引用 | 动态共享功能 | 运行时动态加载的服务 |
案例代码精选
计数器组件(@State基础用法)
@Entry @Component
struct Counter {
@State count: number = 0;
build() {
Column() {
Text(`${this.count}`)
.fontSize(30)
.fontWeight(FontWeight.Bold);
Button("增加")
.onClick(() => {
this.count++;
});
Button("减少")
.onClick(() => {
this.count--;
});
}
}
}
父子组件双向绑定(@Link用法)
// 父组件
@Entry @Component
struct ParentComponent {
@State parentCount: number = 0;
build() {
Column() {
ChildComponent({ childCount: $parentCount })
Button("父组件+1").onClick(() => {
this.parentCount++;
})
}
}
}
// 子组件
@Component
struct ChildComponent {
@Link childCount: number;
build() {
Column() {
Text(`子组件计数: ${this.childCount}`)
Button("子组件+1").onClick(() => {
this.childCount++;
})
}
}
}
持久化存储示例
// 初始化PersistentStorage
PersistentStorage.persistProp('userScore', 100);
// AppStorage获取对应属性
AppStorage.get<number>('userScore'); // returns 100
// 组件中使用
@StorageLink('userScore') score: number = 0;
StateStore全局状态管理
// 定义可观察对象
@ObservedV2
class TodoStoreModel {
@Trace todoList: TodoItemData[] = [];
@Trace isShow: boolean = false;
// 计算属性
@Computed
get uncompletedTodoList(): TodoItemData[] {
return this.todoList.filter(item => !item.selected);
}
}
// 创建状态仓库
const store = StateStore.createStore(new TodoStoreModel(), reducer);
// 组件中使用
const todoList = store.getState().todoList;
降重策略与技巧
- 语义重构:
- 改变句子结构和表达方式
- 主动句与被动句转换
- 拆分长句为短句组合
- 术语替换:
- “状态管理” → “应用数据流转控制”
- “模块化” → “功能组件化拆分”
- “双向绑定” → “数据双向同步机制”
- 数据可视化:
- 将文字描述转为图表展示
- 使用流程图描述架构设计
- 代码示例与文字说明结合
- 原创分析:
- 加入个人对技术的理解
- 对比不同方案的优缺点
- 结合实际应用场景讨论