尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

HarmonyOS 多设备短视频开发 :21 — 状态管理 V1 装饰器体系

HarmonyOS 多设备短视频开发 :21 — 状态管理 V1 装饰器体系 21 — 状态管理 V1 装饰器体系一、引言ArkUI 声明式开发的核心是状态驱动 UI状态变化自动触发依赖该状态的组件刷新。在 HarmonyOS 5.0 之前的版本这套能力由状态管理 V1 装饰器承担包括 State、Prop、Link、Provide、Consume、ObjectLink、Watch 等。本项目multi-short-video已全面升级为 V2 装饰器体系见文章 22但掌握 V1 仍然是必要的一方面存量工程与历史三方库大量使用 V1另一方面V1 的单向数据流 就近管理思想是理解 V2 演进的地基。本文结合项目场景逐一定位 V1 各装饰器的职责与传递规则并指出常见状态不同步问题的根因。二、State组件内状态的最小单元State 装饰的变量由组件自身管理其变化会触发该组件 build 函数的重新执行。以视频页features/multishortvideoadaptivevideo/src/main/ets/view/AdaptiveVideo.ets为例页面需要跟踪当前视频下标、评论弹层开关、播放状态等该项目文件使用 V2 语法等价的 V1 写法如下// 对照示例AdaptiveVideo.ets 相关状态的 V1 等价写法EntryComponentstruct AdaptiveVideo{StatecurIndex:number0;StateshowComment:booleanfalse;StatecurrentState:stringidle;....onAnimationStart((index:number,targetIndex:number){this.curIndextargetIndex;// 直接赋值即可触发刷新this.currentTime0;})}要点State 只作用于组件内部且初始化只能使用本地初始值不能依赖父组件传入的参数。在 Swiper 切换动画回调中直接修改this.curIndexV1 会自动最小化刷新绑定该变量的 UI 节点。三、Prop 与 Link父子组件的单向与双向同步父子组件传参是状态管理最频繁的场景。V1 中Prop 建立单向同步父组件数据变化 → 子组件 Prop 同步更新子组件内部修改 Prop 不会回传父组件。适合只读展示型参数。Link 建立双向同步父子共享同一数据源任一侧修改都会同步到另一侧。适合需要子组件回写的参数。以播放器组件AdaptiveAVPlayer.ets为例父组件 AdaptiveVideo 需要把当前播放下标、视频源、拖拽目标时间传给子组件V1 等价写法// 对照示例AdaptiveAVPlayer.ets 入参的 V1 等价写法Componentexportstruct AdaptiveAVPlayer{PropcurrentIndex:number-1;// 父传子单向同步Propindex:number0;PropcurrentSource:string;PropseekToTime:number-1;// 拖拽进度由父组件写入...Linkduration:number;// 与父组件共享时长双向同步}需要注意Prop 的深拷贝特性决定了它对嵌套对象只同步一层Link 则要求变量类型一致且不能就地初始化由父组件传入。项目中将是否正在拖拽、目标时间等状态统一放在父组件 AdaptiveVideo通过 Prop 单向下发避免了子组件随意回写导致的职责混乱。四、Provide 与 Consume跨层级共享当状态需要在多层组件间传递时逐层 Prop 会形成属性钻透。V1 提供 Provide/Consume 实现跨层级共享祖先组件 Provide 提供数据任意层级后代 Consume 消费同名数据中间层无需感知。本项目首页products/default/src/main/ets/view/Index.ets将深色模式、路由栈、侧栏开关声明在根部供视频页、评论页等多层组件消费V1 等价写法// 对照示例Index.ets 根组件的 V1 等价写法EntryComponentstruct Index{Provide(isDark)isDark:booleanfalse;Provide(pathStack)pathStack:NavPathStacknewNavPathStack();Provide(showSideComment)showSideComment:booleanfalse;Provide(showSideIndividual)showSideIndividual:booleanfalse;...}消费侧如 AdaptiveVideo.ets 的等价写法Consume(showSideComment)showSideComment:boolean;Consume(pathStack)pathStack:NavPathStack;当视频页切换页签需要收起侧栏时直接修改this.showSideComment根组件与所有消费方同步刷新。Provide 默认向全部后代可见若只想对直接子组件可见可配合 Provide 的别名机制控制作用域。五、ObjectLink 与 Watch对象级观察与监听ObjectLink 装饰 class 类型需配合 Observed 类装饰器对对象内部属性变化做深度观察常用于数组项或嵌套对象传入子组件的场景。Watch 为状态变化添加回调在数据变化后触发业务逻辑如保存、上报但 Watch 不提供变化前后的值。以评论数据features/multishortvideocomment/src/main/ets/model/CommentDataModel.ets为例若使用 V1 体系评论对象可声明为 Observed class列表项子组件用 ObjectLink 接收点赞数等属性就地修改即可精准刷新单条评论而不是整表重绘ObservedexportclassCommentDataModel{publiclikes:number0;publiccontent:string;...}// 子组件内Componentexportstruct CommentItem{ObjectLinkitem:CommentDataModel;// 深度观察对象属性Watch(onLikesChange)Proplikes:number0;onLikesChange(){// 点赞数变化后的业务逻辑}}V1 装饰器能力汇总如下表装饰器同步方向支持类型典型场景State组件内基本类型、对象、数组页面局部状态Prop父 → 子单向基本类型、对象一层只读入参Link父子双向与父类型一致需要回写的共享值Provide/Consume祖先 → 后代任意跨多层共享ObjectLink父 → 子深度Observed 对象数组项、嵌套对象Watch监听回调任意 State 等变化后触发逻辑六、V1 常见状态不同步问题排查实践中状态不同步多源于以下几类对象内部属性不刷新普通 class 对象属性变化不会触发 UI 更新必须配合 Observed ObjectLink或整体替换对象引用。Prop 修改不回传误以为 Prop 是双向的在子组件修改后父组件无感知。需要双向时改用 Link。Provide/Consume 名称不匹配两侧 key 必须完全一致含别名写法否则编译期不报错但运行时不生效。ForEach/Repeat 渲染键不稳定用 JSON.stringify(item) 生成键项目在.key((item: AvDataSourceModel) JSON.stringify(item))中采用避免索引键导致的状态错位。在非 UI 线程/回调中修改状态某些异步回调如 AVPlayer 的 stateChange中直接赋值可能错过刷新时机应回到 UI 上下文再赋值。七、总结与最佳实践状态就近声明只被单个组件使用的状态用 State避免无谓提升。参数只读优先 Prop需要回写才用 Link跨层共享优先 Provide/Consume减少逐层透传。对象级数据用 Observed ObjectLink保证细粒度刷新。需要感知状态变化执行副作用保存、埋点、联动播放器时使用 Watch。V1 的就近管理思想是 V2 的基石新项目建议直接采用 V2下一章详解存量工程按需迁移。注文中 V1 示例均为项目既有场景的等价对照写法multi-short-video 实际代码已采用 V2 装饰器迁移思路见文章 22。
返回列表