尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
【ArkUI 入门练中学】第19课:状态管理 V2 深度解析与迁移
本节目标· 理解状态管理 V2 的设计理念掌握其相比 V1 在深度观测与精准刷新上的核心改进· 掌握 ObservedV2 与 Trace 的配合机制能够实现对嵌套对象的自动深度观测· 掌握 V2 组件状态管理装饰器 Local、Param、Once、Event 的用法与 V1 对应关系· 掌握 Monitor 异步监听与 Computed 计算属性的使用理解 V2 监听能力相比 Watch 的增强· 了解 Provider / Consumer、SyncMonitor、Type、ReusableV2 等 V2 新增装饰器· 掌握 AppStorageV2 与 PersistenceV2 的使用方式理解其与 V1 存储方案的对应关系· 掌握从 V1 到 V2 的迁移策略与步骤理解 V1/V2 混用的限制条件· 能够为已有 V1 项目制定合理的 V2 渐进式迁移方案一、状态管理 V2 概述1.1 为什么需要 V2V1 的核心问题在于观测粒度。V1 使用代理来观测数据当创建状态变量时会同时创建一个数据代理观察者。这个机制在简单场景下工作良好但面对嵌套对象时存在根本性局限State 仅能观察对象的第一层属性变化深层嵌套的属性修改无法被感知。V1 通过 Observed ObjectLink 的组合解决了这个问题但代价是需要逐层创建自定义组件每一层都配上 ObjectLink代码复杂度随嵌套深度线性增长。当嵌套层级较深时代码会变得十分复杂易用性差。V2 对状态管理能力进行了全面升级实现了对数据对象的深度观察与管理能力。V2 通过 ObservedV2 和 Trace 装饰器支持对嵌套类对象属性的直接观测无需像 V1 那样依赖 ObjectLink 和自定义组件封装能够直接深度观测无需中间层。1.2 核心理念属性级精准刷新V2 的观测能力实现在类属性上而非组件层级上。V1 的 ObjectLink 观察的是“被 Observed 装饰的类实例”的属性变化而 V2 的 ObservedV2 Trace 将观测能力直接实现在类属性上——当类属性被 Trace 标记时无论嵌套多少层均能观测到变化。这意味着当被 Trace 装饰的属性变化时仅会通知该属性关联的组件进行刷新。这正是 V2 “属性级精准刷新”的核心——不是整个对象刷新不是整个组件刷新而是精确到使用了该属性的 UI 片段刷新。二、ObservedV2 与 Trace深度观测2.1 基本用法ObservedV2 是类装饰器用于状态管理 V2 中。ObservedV2 与 Trace 配套使用装饰类以及类中的属性使得被装饰的类和属性具有深度观测的能力。从 API version 12 开始支持。// 使用ObservedV2类装饰器使 Son 类具有深度观测能力ObservedV2classSon{// 使用Trace装饰器标记需要观测的属性属性变化时触发 UI 刷新Traceage:number100;}classFather{son:SonnewSon();}EntryComponentV2struct Index{father:FathernewFather();build(){Column(){Text(${this.father.son.age})// 设置点击事件点击后 age 值加 1由于Trace装饰器UI 会自动刷新.onClick((){this.father.son.age;})}}}注意Father 类没有被任何装饰器修饰但 Text 组件中使用了 this.father.son.age——当 age 变化时UI 依然会自动刷新。这是因为 Trace 将观测能力实现在了 Son.age 属性上与 Father 无关与组件层级也无关。2.2 嵌套类的观测规则在嵌套类中嵌套类中的属性被 Trace 装饰且嵌套类被 ObservedV2 装饰时才具有触发 UI 刷新的能力。如果嵌套层级中某一层不是 ObservedV2则该层的属性变化无法被追踪。ObservedV2classAddress{Tracecity:string北京;}// 必须也加ObservedV2否则 address.city 的变化无法被观测ObservedV2classUser{Tracename:string张三;address:AddressnewAddress();}关键规则如果 A 持有 BB 的字段要被观测B 本身必须是 ObservedV2 且字段加 Trace。只给外层加是不够的。路径上的每一层对象都需要是可观察的。2.3 与 V1 Observed / ObjectLink 的对比V1 的 Observed ObjectLink 方案要求嵌套对象逐层拆解自定义组件每一层配上 ObjectLink才能实现深度观测。V2 的 ObservedV2 Trace 则直接深度观测可删除中间层自定义组件代码量大幅减少且刷新粒度更细——属性级精准刷新而非组件级刷新。三、V2 组件状态管理装饰器3.1 ComponentV2ComponentV2 用于创建自定义组件是 V2 组件体系的入口。V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错。当组件间不传递变量时V1 的自定义组件中可以使用 V2 的自定义组件。3.2 Local组件内部状态Local 对应 V1 的 State用于装饰组件内部的状态变量。关键差异· 简单类型可以直接将 State 替换为 Local。· 复杂类型V1 中的 State 可以观察复杂对象的第一层属性变化而 V2 中的 Local 只能观察对象自身的变化。如果需要追踪对象内部的属性变化必须结合 ObservedV2 和 Trace。· Local 禁止外部初始化V1 中 State 支持从外部传递初始值V2 中 Local 不允许。若需要从外部传递初始值使用 Param 和 Once。ComponentV2struct Counter{Localcount:number0;// 简单类型直接替换 Statebuild(){Button(计数${this.count}).onClick((){this.count;})}}3.3 Param组件外部输入Param 对应 V1 的 Prop用于接收父组件传递的数据。Param 是单向输入不建议在子组件中直接修改。ComponentV2struct Child{Paramval:number0;// 接收父组件传递的数据build(){Text(child:${this.val})}}3.4 Once初始化同步一次Once 用于 Param表示该参数只在初始化时从父组件同步一次之后父组件的更新不再同步到子组件。需要持续跟随父组件更新时不要给 Param 加 Once。3.5 Event规范组件输出Event 用于规范组件的输出事件通常与 Param 配合实现父子组件双向同步。在 V1 中 Link 允许父子组件之间双向数据绑定迁移到 V2 时可以用 Param 和 Event 模拟双向同步Param 实现父到子的单向传递子组件再通过 Event 回调函数触发父组件的状态更新。ComponentV2struct Child{Paramval:number0;EventaddOne:()void;// 通过回调通知父组件更新build(){Column(){Text(child:${this.val})Button(1).onClick((){this.addOne();// 通过 Event 回调通知父组件更新})}}}EntryComponentV2struct Parent{LocalmyVal:number0;build(){Column(){Text(parent:${this.myVal})Child({val:this.myVal,addOne:()this.myVal// Param 传递数据Event 传递回调})}}}3.6 双向绑定语法糖V2 提供了 !! 双向绑定语法糖用于简化 Param Event 的双向同步场景。其中 Event 方法名需要声明为 $ Param 属性名。// 子组件ComponentV2struct Child{Paramvalue:number0;Event$value:(val:number)void(){};build(){Button(${this.value}).onClick(()this.$value(this.value1))}}// 父组件中使用 !!Child({value:this.myVal!!})四、V2 新增能力Monitor 与 Computed4.1 Monitor状态变量修改异步监听Monitor 是 V2 的状态变量修改监听装饰器对应 V1 的 Watch但能力更强。关键增强Monitor 不仅能够感知变化后的数据还能获取变化前的数据。V1 的 Watch 只能感知变化后的值而 V2 的 Monitor 提供了 IMonitor 接口可以同时获取旧值和新值。ObservedV2classUserModel{Traceage:number0;Tracename:string;}ComponentV2struct DemoPage{Localuser:UserModelnewUserModel();Monitor(user.age)onAgeChange(monitor:IMonitor):void{// monitor.value() 返回本次变更的信息// 可以获取变化前的值和变化后的值console.info(age changed);}build(){Column(){Text(${this.user.age})Button(add).onClick((){this.user.age;})}}}Monitor 不触发的排查首先确认组件必须是 ComponentV2其次被监听的必须是状态变量、Trace 属性或 Computed最后 ObservedV2 实例要通过 new 创建且变化的字段必须加 Trace。路径监听Monitor 支持监听多个属性需要写清楚路径。监听深层对象时要写完整路径如 Monitor(‘user.address.city’)只写 city 只能监听当前作用域下名为 city 的状态。Monitor 是异步合并触发——一次事件里多个属性连续变化通常只回调一次拿到最终状态。如果需要每次赋值都同步触发使用 SyncMonitor。4.2 Computed计算属性Computed 是 V2 新增的计算属性装饰器。V1 无计算属性相关能力V2 可使用 Computed 避免重复计算。在 Computed 中计算的状态变量被改变时计算属性会重新计算。ObservedV2classPriceModel{Traceprice:number0;Tracecount:number1;Computedgettotal():number{returnthis.price*this.count;}}关键规则Computed 只有依赖的 Local、Param、Trace 等状态变化时才会触发 UI 重新计算和刷新。如果 price / count 没有 Trace打印 total 可能是新值但 UI 不一定会被标脏刷新。使用建议对于简单计算不建议使用计算属性因为计算属性本身也有开销。五、V2 全局状态管理5.1 AppStorageV2AppStorageV2 对应 V1 的 AppStorage是应用级内存状态管理方案。当数据变更时自动通知所有依赖组件更新。import{AppStorageV2}fromkit.ArkUI;ObservedV2exportclassPerson{Tracename:string;Traceage:number0;}// 创建或获取存储的数据constpersonAppStorageV2.connect(Person,key,()newPerson());5.2 PersistenceV2PersistenceV2 对应 V1 的 PersistentStorage是应用级数据持久化技术数据直接存在设备磁盘上退出重新进入后数据还存在。import{PersistenceV2}fromkit.ArkUI;// PersistenceV2 作为 AppStorageV2 的持久化引擎constconfigPersistenceV2.connect(AppConfig,config,()newAppConfig());注意V2 状态管理提供的是 AppStorageV2应用级内存状态和 PersistenceV2应用级持久化状态没有 LocalStorageV2。组件局部状态应使用 Local。六、V1 到 V2 迁移指南6.1 迁移策略对于新开发的应用建议直接采用 V2 版本进行开发。 对于已使用 V1 的应用如果 V1 的功能和性能满足需求无需立即切换至 V2。6.2 迁移步骤推荐的迁移节奏是先把组件装饰器换干净再处理数据类的 ObservedV2 化最后接 AppStorageV2、PersistenceV2 和 Repeat。整体门槛是 API 12。第一步组件装饰器替换将 Component 替换为 ComponentV2State 替换为 LocalProp 替换为 Param。注意 Local 禁止外部初始化Param 是只读的。第二步Link 场景处理V1 的 Link 双向绑定拆成 Param Event子组件发事件让父组件更新。或使用 Provider Consumer 实现跨层级双向同步。第三步数据模型 ObservedV2 化将 Observed 替换为 ObservedV2需要观测的属性加 Trace。嵌套类也要各自加 ObservedV2。第四步存储迁移AppStorage → AppStorageV2PersistentStorage → PersistenceV2。消费侧先迁只读页面再迁写入页面。6.3 V1/V2 混用限制V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错。 当组件间不传递变量时V1 的自定义组件中可以使用 V2 的自定义组件。ObservedV2 和 Observed 嵌套使用时类对象能否被 V1 的装饰器装饰取决于最外层 class 使用的装饰器。如果最外层是 Observed 修饰的类可以和 V1 装饰器一起使用。渐进式迁移桥梁老 V1 组件可用 makeV1Observed 把 Observed 实例包装进 V2 体系做渐进式迁移不必一次性全改。七、多元化习题习题 1判断题题目在状态管理 V2 中Local 装饰的复杂对象可以观察其内部嵌套属性的变化无需额外装饰。答案错误解读V2 中的 Local 只能观察对象自身的变化即引用替换不能观察对象内部属性的变化。如果需要追踪对象内部的属性变化必须结合 ObservedV2 和 Trace。习题 2单选题题目以下哪个 V2 装饰器用于标记类属性为可观察使属性变化时触发关联 UI 刷新A. ObservedV2B. TraceC. MonitorD. Computed答案B解读ObservedV2 标记类为可观察Trace 标记类中的属性为可观察。只有被 Trace 装饰的属性变化才会触发 UI 刷新。Monitor 用于监听状态变量变化Computed 用于计算属性。习题 3多选题题目关于 V1 到 V2 的迁移以下说法正确的有多选A. State 在 V2 中对应 Local但 Local 禁止外部初始化B. Link 在 V2 中拆分为 Param EventC. Watch 在 V2 中对应 MonitorMonitor 能获取变化前的数据D. V1 的自定义组件中可以直接使用 V2 的装饰器答案A、B、C解读State 对应 LocalLocal 禁止外部初始化选项 A 正确。Link 拆分为 Param Event选项 B 正确。Watch 对应 MonitorMonitor 能获取变化前的数据选项 C 正确。V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错选项 D 错误。习题 4代码填空题题目请补全以下代码使 User 类的 name 属性变化时能够触发 UI 刷新。______________classUser{______________ name:string张三;age:number25;}答案ObservedV2、Trace解读ObservedV2 装饰类使其具有深度观测能力Trace 装饰需要被观测的属性。只有被 Trace 装饰的属性变化才会触发 UI 刷新age 没有加 Trace其变化不会触发 UI 刷新。习题 5代码改错题题目以下代码存在错误请指出问题并修正。ComponentV2struct Child{Localcount:number0;// 从父组件接收数据build(){Text(${this.count})}}答案Local 禁止外部初始化不能用于接收父组件传递的数据。修正为使用 ParamComponentV2struct Child{Paramcount:number0;// 接收父组件传递的数据build(){Text(${this.count})}}解读Local 是组件内部状态禁止外部初始化。需要从外部传递初始值时应使用 Param。如果需要该参数只在初始化时同步一次可以配合 Once 使用。习题 6简答题题目简述 V2 的 ObservedV2 Trace 相比 V1 的 Observed ObjectLink 的核心优势。答案V1 的 Observed ObjectLink 方案要求嵌套对象逐层拆解自定义组件每一层配上 ObjectLink代码复杂度随嵌套深度线性增长。V2 的 ObservedV2 Trace 将观测能力实现在类属性上当类属性被 Trace 标记时无论嵌套多少层均能观测到变化。核心优势包括无需逐层创建自定义组件直接深度观测属性级精准刷新仅通知使用了该属性的 UI 片段刷新代码量大幅减少可删除中间层自定义组件。解读V2 的核心改进在于将观测能力从“组件层级”下沉到“类属性层级”。V1 需要组件层级配合才能实现深度观测V2 则直接在数据模型层面解决这正是 V2 被称为“能力升级”的根本原因。习题 7简答题题目简述 V1 到 V2 的迁移步骤以及 V1/V2 混用的核心限制。答案迁移步骤第一步将组件装饰器 Component 替换为 ComponentV2State 替换为 LocalProp 替换为 Param。第二步将 Link 双向绑定拆成 Param Event 或使用 Provider Consumer。第三步将 Observed 替换为 ObservedV2需要观测的属性加 Trace嵌套类也要各自加 ObservedV2。第四步将 AppStorage 迁移到 AppStorageV2PersistentStorage 迁移到 PersistenceV2。混用核心限制V1 的自定义组件中不可以使用 V2 的装饰器否则编译报错。当组件间不传递变量时V1 的自定义组件中可以使用 V2 的自定义组件。渐进式迁移可使用 makeV1Observed 将 Observed 实例包装进 V2 体系。解读迁移的核心原则是“逐步替换、渐进过渡”。V1 和 V2 可以在一个工程中共存但不能在一个组件内混用装饰器。迁移时应按组件逐个替换而非一次性全量改造。八、本节知识点总结V2 设计理念V2 将观测能力实现在类属性层级而非组件层级。ObservedV2 Trace 实现属性级精准刷新无需逐层创建自定义组件代码量大幅减少。核心装饰器映射Component → ComponentV2State → LocalProp → ParamLink → Param EventObserved ObjectLink → ObservedV2 TraceWatch → MonitorProvide / Consume → Provider / ConsumerAppStorage → AppStorageV2PersistentStorage → PersistenceV2。深度观测机制ObservedV2 标记类Trace 标记属性。嵌套类也需要各自加 ObservedV2 且字段加 Trace。只有被 Trace 装饰的属性变化才会触发 UI 刷新。V2 新增能力Monitor 支持获取变化前后的数据异步合并触发。Computed 提供计算属性能力避免重复计算。Once 控制 Param 只初始化同步一次。!! 语法糖简化双向绑定。存储方案AppStorageV2 应用级内存状态PersistenceV2 应用级持久化状态。V2 没有 LocalStorageV2组件局部状态使用 Local。迁移策略新项目直接采用 V2。已有 V1 项目逐步迁移建议按“组件装饰器 → 数据模型 ObservedV2 化 → 存储方案”的顺序进行。V1 组件中不能使用 V2 装饰器。下节预告第20课将进入 ArkUI 综合实战项目的学习从需求分析、架构设计到功能实现与性能优化完整走通一个 HarmonyOS 应用的开发全流程。
RELATED

相关推荐

ROS2 Humble 从入门实战教程:第五章 ROS2工作空间与功能包:开发过程的大本营【VMware Ubuntu22.04实操】

ROS2 Humble 从入门实战教程:第五章 ROS2工作空间与功能包:开发过程的大本营【VMware Ubuntu22.04实操】

专栏简介本专栏基于VMware Ubuntu22.04 ROS2 Humble环境,全程实操、全程排坑,适合零基础新手入门学习。本文为第五章核心内容,带你彻底搞懂ROS2两大核心基础:工作空间、功能包,掌握ROS2项目完整组织结构、创建、编译、…

📅 2026/10/10 9:04:52
Codex默认模式提速50%:减少返工与结构化提示词实战

Codex默认模式提速50%:减少返工与结构化提示词实战

我给自己排了一个 28 天的 Codex 实践计划,每天只做一个主题。第一天我没有去背更多高级参数,反而把所有时间花在“默认模式”上。结果有点出乎意料:同样两个改代码的任务,完成时间从 120 分钟压到 65 分钟左右,换算下…

📅 2026/10/10 9:04:52
DeepSeek提升自动化测试效率:用例生成、失败分析与AI维护实战

DeepSeek提升自动化测试效率:用例生成、失败分析与AI维护实战

搞自动化测试这些年,我最大的感受就是:用例维护比写用例累十倍,断言写不好等于白测,环境一崩全队emo。所以当 DeepSeek 这类 AI 工具开始把编程能力拉到接近普通工程师水平之后,我第一反应不是拿它写业务代码&#xff…

📅 2026/10/10 9:04:52
MORE NEWS

更多资讯

📰

PJ85718DM+MKV42F128VLH16工业温控信号链设计

1. 项目概述:为什么两个看似不相关的芯片组合,成了温控系统的“黄金搭档”你有没有遇到过这样的场景:在调试一台新部署的HVAC(暖通空调)控制面板时,本地温度传感器读数稳定,但远程监控平台却频繁…

📰

Muse与Dots竞逐消费级AI agent;700篇AI证明引发数学家抵制 | 科技日报1009

700篇AI证明引发数学家抵制 #1人类数学协会(AHM)呼吁数学家停止与OpenAI合作。该协会认为,在 OpenAI 一次性发布数百篇 AI 生成的数学手稿后,公司违反了科学研究的基本规范。协会主席、菲尔兹奖得主陶哲轩以客座文章形式在自己的博…

📰

OpenHarmony实战:MAX30100血氧心率传感器驱动开发从零到通

这几年可穿戴设备火起来之后,血氧心跳传感器MAX30100成了很多人入门嵌入式开发的第一个目标芯片;而要在OpenHarmony系统上把这颗芯片的驱动开发做通,绕不开I2C协议、PPG采集和底层算法几个硬骨头。手头正好有一块基于OpenHarmony的开发板&…

📰

CMake 策略 CMP0107 详解:禁止 ALIAS 目标覆盖同名已有目标

构建工具开发工具CLI 【免费下载链接】CMake Mirror of CMake upstream repository 项目地址: https://gitcode.com/gh_mirrors/cm/CMake 点击查看 免费下载 导读 CMP0107 是 CMake 3.18 引入的一项兼容性策略,核心内容是:不允许创建一个与…

📰

用 __android_log_print(ANDROID_LOG_DEBUG, 打印出data_ptr[i]的值

在Android NDK开发中&#xff0c;__android_log_print 函数用于将日志信息输出到Logcat。如果你想打印出指针 data_ptr 指向的数组中第 i 个元素的值&#xff0c;你可以使用以下代码&#xff1a;cpp #include <android/log.h>// 假设 data_ptr 是一个指向 unsigned char …

📰

Flink电商实时计算实战:从Kafka到五大核心指标

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬