【HarmonyOS学习笔记】2026-07-16 | 状态管理V2

发布时间:2026/7/17 3:29:59
【HarmonyOS学习笔记】2026-07-16 | 状态管理V2 【HarmonyOS学习笔记】2026-07-16 | 状态管理V2date: 2026-07-16tags: [HarmonyOS, 状态管理V2, Local, Param, Event, Once, ComponentV2, 职责不清, 重绘]1️⃣ 学习内容概览学习状态管理V2的核心装饰器Local数据拥有者、Param数据接收者父→子单向同步、Event子→父事件通知、Once锁住Param只同步一次以及V2组件声明方式ComponentV2。重点深入了三个问题① Event 传事件类型 vs 传具体新值——从谁决定新值到职责不清的四层递进分析② Event 到底比 Param 传回调多做了什么——官方文档解读对照实验推论修正目前待解③ Once 的行为证明重绘≠重新初始化。2️⃣ 核心知识点与实操问题一、V1 → V2 对应关系V1V2角色变化理由StateLocal数据拥有者自带初始值改名强调本地拥有PropParam数据接收者父→子单向同步改名强调参数传入(无)Event子→父事件通知V2新增替代V1隐式双向绑定Link(取消)—V2取消了双向绑定改用ParamEvent显式实现ComponentComponentV2V2组件声明V2装饰器必须配合此声明V2的核心变化取消Link双向绑定改用Param单向输入 Event事件输出显式实现双向数据流。二、Local、Param、Event 三者定位Local — 数据拥有者组件自己拥有、自己管理、自己初始化拥有完整控制权读、写、决定怎么响应下级的申请只能通过Param把值下发给下级下级可读不可改Param — 数据接收者从父组件接收值单向同步父→子子组件只能读不能对Param赋值父重绘时值会同步更新除非加了OnceEvent — 事件通知者子组件向父组件发送事件通知的通道函数体由父组件提供决定怎么响应参数由子组件提供传递发生了什么回调同步执行返回void不是Promise官方定位Param 组件的输入(in)Event 组件的输出(out)完整链路Local(父) → Param传参 → 子组件UI渲染 → 用户点击按钮 → Event回调触发 → 修改Local(父) → 父重绘 → Param值同步更新 → 子重绘权力模型上级 Local拥有者 ├── Param → 下级可读不可改 └── ← Event → 下级可申请上级决定是否改、怎么改三、Event 传什么参数——从谁决定新值到职责不清核心重点学习教材示例时我的写法和教材写法不同对比之后引发了一连串越来越深的讨论。3.1 两种写法教材写法——传事件类型// 父组件 Entry ComponentV2 struct Index { Local title: string Title One; Local fontColor: Color Color.Red; build() { Column() { Child({ title: this.title, fontColor: this.fontColor, changeFactory: (type: number) { if (type 1) { this.title Title One; this.fontColor Color.Red; } else if (type 2) { this.title Title Two; this.fontColor Color.Green; } } }) } } } // 子组件 ComponentV2 struct Child { Param title: string ; Param fontColor: Color Color.Black; Event changeFactory: (type: number) void (type: number) {}; build() { Column() { Text(${this.title}) .fontColor(this.fontColor) Button(change to Title Two) .onClick(() { this.changeFactory(2); // 只传选了方案2 }) Button(change to Title One) .onClick(() { this.changeFactory(1); }) } } }我的写法——传具体新值// 父组件 Entry ComponentV2 struct Index { Local title: string Title One; Local fontColor: Color Color.Red; build() { Column() { Child({ title: this.title, fontColor: this.fontColor, changeFactory: (title: string, fontColor: Color) { this.title title; // 父照办 this.fontColor fontColor; // 父照办 } }) } } } // 子组件 ComponentV2 struct Child { Param title: string ; Param fontColor: Color Color.Black; Event changeFactory: (title: string, fontColor: Color) void (title: string, fontColor: Color) {}; build() { Column() { Text(${this.title}) .fontColor(this.fontColor) Button(change to Title Two) .onClick(() { this.changeFactory(Title Two, Color.Green); // 直接传新值 }) Button(change to Title One) .onClick(() { this.changeFactory(Title One, Color.Red); }) } } }3.2 第一层谁决定新值表面看区别是谁决定新值教材传事件类型我传具体新值子组件说“客户选了方案2”“请把标题改成’Title Two’颜色改成Green”父组件做自己决定方案2对应什么照单全收类比员工通知老板发生了什么→老板决定员工告诉老板该怎么做→老板照办决策权父组件子组件越权替父决定新值结论教材更合理——子组件通知事件父组件决定响应。3.3 第二层上级是否拥有知情权和审批权真正的问题不是谁决定而是上级知不知道下级在干什么。教材传事件类型我传具体新值上级知道什么知道所有可能的流程和结果只知道下级要改不知道改什么上级的角色决策者审批执行橡皮图章只执行不审批下级能传意外值吗不能——type只能是1或2上级if覆盖了所有情况能——传什么值上级都照办没有校验可控性✅ 上级可控❌ 上级失控根因是职责不清教材下级申请执行哪个流程上级定义流程内容审批通过后执行——职责清晰我的写法下级提交执行令具体新值上级盖章通过但根本没看内容——职责不清名义上上级在管Local是上级的回调体也在上级里实际上下级在决策决定改什么值上级只是执行工具。上级丧失了知情权和审批权变成了橡皮图章。3.4 第三层V1 → V2 的职责演变我的写法其实延续了V1 Link的思维惯性V1 LinkV2 我的写法V2 教材写法职责归属清晰但松——上下级共享修改权模糊——名义上级管实际下级管清晰且严——上级独占决策权上级知情权✅ 知道双向同步❌ 不知收到啥赋啥✅ 知道自己定义流程上级审批权❌ 没有子直接改❌ 没有照单全收✅ 有if逻辑就是审批结论V1的问题是权限太松我的V2写法是换了形式但问题没解决职责不清教材的V2才是真正解决了问题——权限收紧职责清晰。⚠️ 关于V2意图是让上级独占决策权这一点是我的推论官方文档没有明确这样表述。官方明确的是取消Link双向绑定、Param单向同步、Event通知机制。传事件类型不传具体值是推荐模式不是语法强制——两种写法都能编译通过但在职责清晰度上有本质差异。3.5 第四层Event 到底比 Param 传回调多做了什么讨论到这里一个新问题浮出水面Event 作为装饰器到底比 Param 传回调多做了什么我之前的推论Event避免回调引用变化导致的子组件不必要重绘类似React的useCallback。实验否定了这个推论。回调函数不绑定任何UI控件属性——它只在.onClick()事件里被调用不在Text()、Button()等组件的渲染属性里出现。即使回调引用变了框架也没有理由因为一个不参与渲染的值去触发子组件重绘。对照实验写法效果Event changeFactory✅ 功能正常Param changeFactory✅ 功能正常肉眼无差异无装饰changeFactory❌ 报错ComponentV2要求外部传入的属性必须用装饰器关键发现Param和Event传回调在功能上无可见差异。四、Event 官方文档解读与待解问题4.1 官方文档关键原文“为了实现子组件向父组件要求更新Param装饰变量的能力开发者可以使用Event装饰器”“Event主要配合Param实现数据的双向同步”“使用Event装饰回调方法是一种规范表明子组件需要传入更新数据源的回调”“Param标志着组件的输入表明该变量受父组件影响而Event标志着组件的输出可以通过该方法影响父组件”两次提到规范这个词4.2 官方定位总结Param 输入(in)Event 输出(out)ParamEvent 双向同步。官方自己把ParamEvent的组合定义为双向同步——这意味着V2并没有取消双向数据流只是用显式的输入输出替代了V1 Link的隐式双向绑定。V1 LinkV2 Param Event本质隐式双向绑定——子直接改父显式双向同步——子申请父改再同步回来方向双向但不可见双向且方向可见Param(父→子) Event(子→父)子组件权力直接修改只能申请代码可读性看不出数据流方向一眼看出输入/输出4.3 之前推论的修正推论状态说明“Event避免回调引用变化导致的子组件重绘”❌ 已否定回调函数不绑定UI控件属性不存在因引用变化触发重绘的问题“Event让上级拥有审批权”⚠️ 部分成立取决于回调函数怎么写Event本身不强制审批逻辑“Event是规范声明标注输入/输出方向”✅ 官方原文支持官方两次提到规范明确Param输入、Event输出4.4 待解问题既然Param和Event传回调在功能上无可见差异Event比Param多做了什么官方强调规范但规范的具体技术意义框架内部是否有不同处理尚未理解目前没有找到Event相比Param传回调的实质功能差异只记录发现不做过早结论五、Once 的作用Param Once title: string ; // 只接收一次初始值 Param Once fontColor: Color Color.Black; // 之后不再同步Once 的含义“只接收一次之后不再同步”。第一次初始化时拿到值之后父组件怎么变都不管——Param 和父组件之间的同步通道被切断。实验现象加了Once后点击按钮→Event回调→Local修改→父重绘但子组件UI不变。原因父重绘时 Param 本应同步更新但 Once 锁住了不再更新子不重绘。Once 的使用场景子组件只需要初始值、不需要跟随变化的场景比如初始化配置项。不要随意加——加了之后Event回调改了Local子组件也收不到新值UI不会变。六、Param 重绘 ≠ 重新初始化正常流程无Once Local 变 → 父重绘 → Param 值同步更新 → 子重绘 → UI 变化 ✅ 加了Once后 Local 变 → 父重绘 → Param 被Once锁住不更新 → 子不重绘 → UI 不变 ❌Once 证明是重绘不是重新初始化如果是重新初始化Once也挡不住初始化就是第一次正因为是重绘时的值同步更新Once才能拦住第二次及之后的更新。加Once后点击不变化直接实锤了这个结论。组件实例始终同一个Param值会同步更新无Once时但Event不会重新注册组件不会重新创建。重绘是值的更新不是实例的销毁重建。3️⃣ 为什么这些问题出现刨根问底 我的理解1. Event 的核心问题是职责不清传具体新值的写法看似上级在修改自己的状态Local是上级的回调体也在上级里实际上下级在决策决定改什么值上级只是执行工具。上级丧失了知情权和审批权变成橡皮图章——名义上上级管实际上下级管。教材的写法之所以更合理不是因为语法强制而是因为它保持了职责清晰下级申请执行哪个流程上级定义流程并审批执行。2. 我的写法延续了V1 Link的思维惯性V1时Link允许子组件直接修改父组件状态子组件拥有决策权。我在V2中虽然用了Event但传的是具体新值、上级照办本质还是子组件决策——用V2的管道跑了V1的逻辑。V2取消Link、改用Param单向Event通知我猜测其意图可能是纠正V1的职责不清问题但这一点是推论官方未明确声明。3. Event vs Param传回调——待解实验发现Param和Event传回调在功能上无可见差异。官方两次提到规范将Param定位为输入、Event定位为输出说Event主要配合Param实现数据的双向同步。但Param传回调同样能实现双向同步Event多出来的部分到底是什么——目前没有答案。之前推论Event避免回调引用变化导致重绘已被否定回调不绑定UI属性不存在重绘问题。只记录发现不做过早结论。4. Once 的存在意义某些场景下子组件只需要初始值不需要跟随父组件变化比如初始化配置项Once提供了这种只同步一次的能力同时它的行为也揭示了V2的更新机制是重绘时值同步而非销毁重建。4️⃣ 实操验证记录#问题现象排查过程解决1Event该传事件类型还是具体值我的代码传具体值(title,fontColor)教材传类型编号(type)对比教材代码分析两种写法的决策权归属教材更合理子通知事件父决定响应2传具体新值到底有什么问题表面上上级在修改状态实际上下级在决策逐步深入谁决定新值→上级是否有知情权→职责是否清晰根因是职责不清上级丧失知情权和审批权变成橡皮图章3Once有什么效果加Once后点击按钮UI不变分析链路Local变→父重绘→Param被锁→子不重绘Once锁住Param只同步一次证明重绘≠重新初始化4Event比Param传回调多做了什么Param和Event传回调功能完全一样无可见差异对照实验同一回调分别用Param/Event/无装饰观察UI行为查阅官方文档无结论。Param/Event功能无差异无装饰报错官方只说规范。待解5Event避免重绘推论是否成立假设Event比Param能避免回调引用变化导致的子组件重绘分析回调函数不绑定UI控件属性只在onClick里调用不在渲染属性里出现引用变化不会触发重绘❌ 推论已否定——回调不参与渲染不存在重绘问题5️⃣ 最终结论最佳实践维度建议Event参数设计传事件类型/标识不传具体新值保持上级知情权和审批权职责清晰Event vs Param传回调功能无差异Event是规范声明Param输入Event输出但具体技术意义待解Once使用场景仅在只需初始值、不跟随变化时使用不要随意加V1迁移V2State→Local, Prop→Param, Link→ParamEvent显式双向, Component→ComponentV2ComponentV2V2装饰器必须配合ComponentV2使用不能用ComponentV2双向同步ParamEvent实现显式双向同步官方原文替代V1 Link隐式双向绑定重绘机制V2更新是重绘时值同步而非销毁重建Once行为实锤此结论// Event 最佳实践传事件类型父组件决策职责清晰 Entry ComponentV2 struct Index { Local title: string Title One; Local fontColor: Color Color.Red; build() { Column() { Child({ title: this.title, fontColor: this.fontColor, changeFactory: (type: number) { if (type 1) { this.title Title One; this.fontColor Color.Red; } else if (type 2) { this.title Title Two; this.fontColor Color.Green; } } }) } } } ComponentV2 struct Child { Param title: string ; Param fontColor: Color Color.Black; Event changeFactory: (type: number) void (type: number) {}; build() { Column() { Text(${this.title}) .fontColor(this.fontColor) Button(change to Title Two) .onClick(() { this.changeFactory(2); }) Button(change to Title One) .onClick(() { this.changeFactory(1); }) } } }// Once 使用只接收初始值之后不跟随变化 ComponentV2 struct ConfigItem { Param Once initialConfig: string ; // 只拿一次后续不更新 Local innerState: number 0; build() { Column() { Text(Config: ${this.initialConfig}) // 永远显示初始值 Button(Count: ${this.innerState}) .onClick(() { this.innerState; }) } } }核心原则Event是通知不是命令——子组件告诉父组件发生了什么事父组件自己决定怎么响应。传事件类型保持职责清晰上级拥有知情权和审批权传具体新值会让上级变成橡皮图章。V2的ParamEvent实现显式双向同步官方原文替代V1 Link的隐式双向绑定。重绘≠重新初始化Once行为实锤此结论。学习小结状态管理V2用Local/Param/Event明确了数据拥有者和方向。Event传具体新值看似上级在管实际上下级在决策——职责不清才是根本问题根因是上级丧失了知情权和审批权。教材传事件类型的写法保持了上级的知情权和审批权职责清晰。我的写法延续了V1 Link的思维惯性——用V2的管道跑了V1的逻辑。官方文档将Param定位为输入、Event定位为输出说Event主要配合Param实现数据的双向同步两次提到规范但实验发现Param和Event传回调在功能上无可见差异Event相比Param多做了什么——目前待解不做过早结论。之前推论Event避免回调引用变化导致重绘已被否定。Once锁住Param只同步一次证明V2的更新机制是重绘时值同步而非销毁重建。懿路向前 · AI辅助整理2026-07-16