本文系统讲解鸿蒙ArkUI状态管理V2,带你从入门到实战
大家好!今天要给大家分享的是鸿蒙开发中非常重要的状态管理。
我们在开发APP时,最常见的需求就是:数据变化时,UI要自动更新。比如:
用户点击按钮,计数+1,数字要自动变化
输入框输入文字,下面的列表要自动过滤
删除一条数据,列表要自动少一条
这些看似简单的功能,在传统开发中需要手动编写大量代码。但有了状态管理V2,一切变得非常简单!
1.1 生活中的例子
想象一下,你在餐厅点餐:
在这个过程中:
你 = 用户(操作UI)
点餐内容 = 状态(数据)
服务员 = 状态管理系统(负责同步)
做菜 = 业务逻辑处理
服务员(状态管理)把你的需求告诉厨房(数据层),厨房做好了自动端给你(UI自动更新),你不需要跑去厨房看菜做好了没有。
1.2 技术上的定义
状态管理 = 数据 + UI同步机制当数据变化时,UI自动更新,无需手动操作。
在鸿蒙中,状态管理是基于MVVM架构模式实现的。
2.1 什么是MVVM?
2.2 数据流向
核⼼优势:数据驱动UI,开发者只需关注数据变化,UI⾃动更新!
鸿蒙状态管理V2提供了⼀系列强⼤的装饰器:
4.1 什么是@Local?
@Local 用于管理组件内部的状态。被它装饰的变量变化时,UI会自动更新。
4.2 基本语法
4.3 简单示例:计数器
@Entry@Componentstruct CounterPage { @Local count: number = 0; // 定义状态 build() { Column({ space: 20 }) { // 显示计数 - 自动更新! Text('当前计数: ' + this.count) .fontSize(30) // 按钮点击,状态变化 Button('点我+1') .onClick(() => { this.count++; // 状态变化,UI自动刷新 }) } }}
@Entry@Componentstruct TaskDemo { @Local isFinished: boolean = false; // 任务完成状态 build() { Row({ space: 15 }) { // 根据状态显示不同图标 Image(this.isFinished ? $r('app.media.ic_checked') : $r('app.media.ic_unchecked')) .width(24) // 任务文字 - 带删除线效果 Text('学习鸿蒙开发') .fontSize(18) .decoration({ type: this.isFinished ? TextDecorationType.LineThrough : TextDecorationType.None }) } .onClick(() => { this.isFinished = !this.isFinished; // 点击切换 }) }}
5.1 什么是@Param?
@Param 让⼦组件可以接收⽗组件传⼊的数据。实现⽗→⼦的单向数据流。
5.2 基本语法
// 子组件接收@Componentstruct ChildComponent { @Param 变量名:类型; // 只读 @Param @Once 变量名:类型; // 可修改(仅初始化一次)}
// 子组件:任务项@Componentstruct TaskItem { @Param taskName: string = ''; // 接收任务名称 @Param @Once isFinished: boolean = false; // 接收初始状态,可修改 build() { Row({ space: 15 }) { Image(this.isFinished ? $r('app.media.ic_checked') : $r('app.media.ic_unchecked')) .width(24) Text(this.taskName) .fontSize(16) .decoration({ type: this.isFinished ? TextDecorationType.LineThrough : TextDecorationType.None }) } .onClick(() => { this.isFinished = !this.isFinished; // 修改状态 }) }}// 父组件:任务列表@Entry@Componentstruct TodoList { private taskList: string[] = [ '学习鸿蒙开发', '完成作业', '运动健身' ]; build() { Column() { ForEach(this.taskList, (name: string) => { TaskItem({ taskName: name }) // 传递数据给子组件 }) } }}
5.4 数据流向
6.1 什么是@Event?
@Event ⽤于⼦组件向⽗组件输出事件/通知。实现⼦→⽗的单向通信。
6.2 基本语法
// ⼦组件定义@Componentstruct ChildComponent {@Event onDelete: (id: number) => void; // 定义事件build() {Button('删除') .onClick(() => {this.onDelete(1); // 触发事件 }) }}
// 子组件@Componentstruct TaskItem { @Param taskName: string = ''; @Param taskId: number = 0; @Event onDelete: (id: number) => void; build() { Row({ space: 15 }) { Text(this.taskName).layoutWeight(1) Button('删除') .onClick(() => { this.onDelete(this.taskId); // 通知父组件删除 }) } }}// 父组件@Entry@Componentstruct TodoList { @Local tasks: Task[] = [ new Task(1, '学习鸿蒙'), new Task(2, '写代码'), new Task(3, '运动') ]; deleteTask(id: number) { this.tasks = this.tasks.filter(t => t.id !== id); // 删除逻辑 } build() { Column() { ForEach(this.tasks, (task: Task) => { TaskItem({ taskName: task.name, taskId: task.id, onDelete: (id) => { this.deleteTask(id); // 处理删除事件 } }) }) } }}class Task { id: number; name: string; constructor(id: number, name: string) { this.id = id; this.name = name; }}
6.4 @Param + @Event 双向通信
学会这两个装饰器,你就可以实现⽗⼦组件的完美通信!
七、@ObservedV2 + @Trace:对象属性观测7.1 什么是@ObservedV2?
当需要管理对象数据时,普通装饰器可能不够⽤。@ObservedV2 让对象的属性变化可以被追踪。
7.2 什么是@Trace?
@Trace 精确指定哪些属性需要追踪变化。只追踪被装饰的属性,优化性能。
7.3 基本语法
@ObservedV2class 类名 { @Trace 属性名:类型 = 初始值; // 追踪这个属性 属性名:类型 = 初始值; // 不追踪}
// 定义可观测的任务类@ObservedV2class Task { @Trace name: string = ''; // 追踪:名称变化 @Trace isFinished: boolean = false; // 追踪:状态变化 deadline: string = ''; // 不追踪:不影响UI constructor(name: string) { this.name = name; }}// 使用@Entry@Componentstruct TaskPage { @Local task: Task = new Task('学习鸿蒙'); build() { Column() { Text(this.task.name) // 变化时自动更新 Text(this.task.isFinished ? '已完成' : '进行中') // 变化时自动更新 Text(this.task.deadline) // 变化时不会更新 Button('完成任务') .onClick(() => { this.task.isFinished = true; // 触发UI更新 }) } }}
7.5 ⼯作原理
8.1 什么是Repeat?
Repeat 是鸿蒙提供的⾼效列表渲染组件,特别适合渲染⼤量数据。
8.2 两种模式
8.3 基本语法
// ⾮懒加载Repeat(数组).each((item) => {// 渲染每个item})// 懒加载Repeat(数组) .lazy(true) .each((item) => {// 渲染 })
8.4 示例:任务列表
@Entry@Componentstruct TaskList { @Local tasks: string[] = [ '学习鸿蒙开发', '完成作业', '运动健身', '阅读书籍' ]; build() { Column({ space: 10 }) { // 使用 Repeat 渲染 Repeat(this.tasks).each((taskName: string) => { Row({ space: 15 }) { Text(taskName) } .width('100%') .padding(16) .backgroundColor('#FFFFFF') }) } .padding(20) }}
九、AppStorageV2 + PersistenceV2:全局存储9.1 存储⼯具对⽐
9.2 AppStorageV2:全局共享
import { AppStorageV2 } from '@kit.ArkUI';// 存储数据AppStorageV2.setOrCreate('username', '小明');AppStorageV2.setOrCreate('theme', 'dark');// 读取数据const username = AppStorageV2.get<string>('username');const theme = AppStorageV2.get<string>('theme');// 删除数据AppStorageV2.delete('username');// 检查是否存在const hasKey = AppStorageV2.has('username');
import { PersistenceV2 } from '@kit.ArkUI';// 存储数据(⾃动持久化,APP关闭后不丢失)PersistenceV2.setOrCreate('userToken', 'abc123');PersistenceV2.setOrCreate('userSettings', { theme: 'dark', lang: 'zh' });// 读取数据const token = PersistenceV2.get<string>('userToken');// 删除数据PersistenceV2.delete('userToken');// 清空所有PersistenceV2.clear();
import { PersistenceV2 } from '@kit.ArkUI';// Key定义const KEY_IS_LOGGED_IN = 'isLoggedIn';const KEY_USERNAME = 'username';@Entry@Componentstruct LoginPage { @Local username: string = ''; @Local isLoggedIn: boolean = false; aboutToAppear() { // 读取持久化数据 this.isLoggedIn = PersistenceV2.get<boolean>(KEY_IS_LOGGED_IN) ?? false; this.username = PersistenceV2.get<string>(KEY_USERNAME) ?? '未登录'; } login() { // 登录成功,保存状态 this.isLoggedIn = true; this.username = '小明'; PersistenceV2.setOrCreate(KEY_IS_LOGGED_IN, true); PersistenceV2.setOrCreate(KEY_USERNAME, '小明'); } logout() { // 退出登录,清除状态 this.isLoggedIn = false; this.username = '未登录'; PersistenceV2.delete(KEY_IS_LOGGED_IN); PersistenceV2.delete(KEY_USERNAME); } build() { Column({ space: 20 }) { if (this.isLoggedIn) { Text('欢迎,' + this.username + '!') Button('退出登录') .onClick(() => this.logout()) } else { Text('请登录') Button('登录') .onClick(() => this.login()) } } }}
让我们综合运⽤所有知识,实现⼀个完整的待办事项应⽤!
完整代码
import { PersistenceV2 } from '@kit.ArkUI';// 定义任务类@ObservedV2class Task { @Trace id: number = 0; @Trace name: string = ''; @Trace isFinished: boolean = false; constructor(id: number, name: string) { this.id = id; this.name = name; this.isFinished = false; }}// 持久化Keyconst KEY_TASKS = 'tasks';// 任务项组件@Componentstruct TaskItem { @Param task: Task = new Task(0, ''); @Event onToggle: () => void; @Event onDelete: () => void; build() { Row({ space: 15 }) { Checkbox() .select(this.task.isFinished) .onChange(() => this.onToggle()) Text(this.task.name) .fontSize(16) .layoutWeight(1) .decoration({ type: this.task.isFinished ? TextDecorationType.LineThrough : TextDecorationType.None }) Button('删除') .fontSize(12) .type(ButtonType.Capsule) .backgroundColor(Color.Red) .onClick(() => this.onDelete()) } .width('100%') .padding(16) .backgroundColor('#FFFFFF') .borderRadius(8) }}// 主页面@Entry@Componentstruct TodoApp { @Local tasks: Task[] = []; aboutToAppear() { this.loadTasks(); } loadTasks() { const saved = PersistenceV2.get<Task[]>(KEY_TASKS); if (saved) { this.tasks = saved.map(t => new Task(t.id, t.name)); } } saveTasks() { PersistenceV2.setOrCreate(KEY_TASKS, this.tasks); } addTask(name: string) { this.tasks.push(new Task(this.tasks.length + 1, name)); this.saveTasks(); } toggleTask(id: number) { const task = this.tasks.find(t => t.id === id); if (task) { task.isFinished = !task.isFinished; this.saveTasks(); } } deleteTask(id: number) { this.tasks = this.tasks.filter(t => t.id !== id); this.saveTasks(); } build() { Column({ space: 15 }) { Text('我的待办') .fontSize(28) .fontWeight(FontWeight.Bold) // 渲染任务列表 ForEach(this.tasks, (task: Task) => { TaskItem({ task: task, onToggle: () => this.toggleTask(task.id), onDelete: () => this.deleteTask(task.id) }) }) // 添加任务 Button('+ 添加任务') .width('100%') .onClick(() => { this.addTask('新任务' + (this.tasks.length + 1)); }) } .width('100%') .padding(20) .backgroundColor('#F5F5F5') }}
功能特点
✅ 添加任务
✅ 删除任务
✅ 标记完成状态
✅ 数据持久化(关闭APP不丢失)
✅ @ObservedV2 + @Trace 精确追踪
✅ @Param + @Event ⽗⼦通信
11.1 知识体系回顾
11.2 选择指南
11.3 学习路径
恭喜你!已经掌握了鸿蒙状态管理V2的核⼼知识!
状态管理是鸿蒙开发的基础,也是进阶的必经之路。掌握这些知识点后,你就可以轻松实现各种交 互逻辑,开发出流畅的APP了。 如果觉得⽂章对你有帮助,欢迎点赞收藏!
有问题也可以在评论区留⾔讨论~
本文作者:誉天HarmonyOS资深讲师——王琦老师