鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信
掌握跨级组件通信构建灵活可复用的组件体系一、前言在复杂应用中经常出现祖先组件需要向后代组件传递数据的场景。如果逐层通过 Prop 传递会导致属性逐层传递的问题prop drilling代码冗长且难以维护。ArkUI 提供了 Provide/Consume 装饰器对实现跨级组件通信无需中间组件参与。二、Provide/Consume 原理2.1 基本概念Provide 祖先组件 │ │ (自动传递) │ v Consume 后代组件 1 Consume 后代组件 2Provide在祖先组件中定义提供数据Consume在后代组件中声明自动获取祖先的 Provide 数据2.2 基础用法// 祖先组件 - 提供数据Componentstruct AppRoot{Provide(isLoggedIn)isLoggedIn:booleanfalse;Provide(userName)userName:string;build(){Column(){// 中间组件不需要传递任何数据MainContent();}}}// 中间组件 - 不接触数据Componentstruct MainContent{build(){Column(){UserProfile();}}}// 后代组件 - 消费数据Componentstruct UserProfile{Consume(isLoggedIn)isLoggedIn:boolean;Consume(userName)userName:string;build(){Column(){if(this.isLoggedIn){Text(欢迎,${this.userName}).fontSize(18);}else{Button(登录);}}}}2.3 类型推断省略别名当不指定别名时Provide/Consume 使用变量名自动匹配Componentstruct Ancestor{ProvidestepCount:number0;// 变量名作为标识build(){Descendant();}}Componentstruct Descendant{ConsumestepCount:number;// 自动匹配同名变量// 等价于 Consume(stepCount) stepCount: number;build(){Text(步数:${this.stepCount});}}三、Provide/Consume vs Prop/Link特性Prop/LinkProvide/Consume传递层级父子之间任意层级中间组件需要逐层传递无需参与使用场景直接父子跨级祖先→后代性能较好稍差需查找可读性显式传递隐式传递选择建议父子组件用 State/Prop/Link跨 2 层以上用 Provide/Consume全局状态用 AppStorage四、实战徒步迹全局登录状态在徒步迹 App 中登录状态需要在多个页面间共享// AppRoot - 应用根组件EntryComponentstruct AppRoot{Provide(isLogged)isLogged:booleanfalse;Provide(currentUser)currentUser:User|nullnull;Provide(themeMode)themeMode:stringlight;build(){Column(){if(!this.isLogged){LoginPage();}else{MainTabPage();}}.width(100%).height(100%);}}4.1 登录页面使用Componentstruct LoginPage{Consume(isLogged)isLogged:boolean;Consume(currentUser)currentUser:User|null;build(){Column(){Button(登录).onClick((){// 成功后更新全局状态this.isLoggedtrue;this.currentUser{id:1,nickname:徒步爱好者,avatar:,phone:138****0000,};});}}}4.2 个人中心页面使用Componentstruct ProfilePage{Consume(isLogged)isLogged:boolean;Consume(currentUser)currentUser:User|null;build(){Column(){if(this.currentUser){Text(this.currentUser.nickname).fontSize(20).fontWeight(FontWeight.Bold);Text(手机:${this.currentUser.phone}).fontSize(14).fontColor(#666);}Button(退出登录).onClick((){this.isLoggedfalse;this.currentUsernull;});}}}五、多个 Provide/Consume 的协作// 追踪页 - 提供多个状态Componentstruct TrackingSection{Provide(status)status:stringidle;Provide(trackData)trackData:TrackData{duration:0,distance:0,points:[],};build(){Column(){ControlPanel();StatsDisplay();MapView();}}}// 控制面板 - 修改状态Componentstruct ControlPanel{Consume(status)status:string;Consume(trackData)trackData:TrackData;build(){Button(开始).onClick((){this.statusrecording;});}}// 统计显示 - 读取状态Componentstruct StatsDisplay{Consume(trackData)trackData:TrackData;build(){Text(距离:${trackData.distance.toFixed(2)}km);}}六、AppStorage - 应用级全局存储除了 Provide/ConsumeArkUI 还提供了 AppStorage 用于应用级状态管理// 1. 在 Ability 中初始化exportdefaultclassEntryAbilityextendsUIAbility{onCreate():void{AppStorage.setOrCreate(token,);AppStorage.setOrCreate(userId,0);AppStorage.setOrCreate(stepGoal,10000);}}// 2. 在组件中使用EntryComponentstruct HomePage{StorageLink(token)token:string;StorageProp(stepGoal)stepGoal:number10000;build(){Text(目标步数:${this.stepGoal});}}API说明StorageLink(key)双向绑定组件修改同步到 AppStorageStorageProp(key)单向绑定组件只读AppStorage.set()设置值AppStorage.getT(key)获取值AppStorage.setOrCreate(key)不存在时创建七、LocalStorage - 页面级共享LocalStorage 是 Ability 或页面级别的共享存储// 创建页面级存储letlocalStoragenewLocalStorage({pageTitle:徒步迹,pageType:home,});// 在页面中使用Entry(localStorage)Componentstruct HomePage{LocalStorageLink(pageTitle)title:string;build(){Text(this.title);}}八、状态管理选择指南应用级全局数据 ├── 是 → AppStoragetoken、用户信息、设置 └── 否 → 组件间层级 ├── 跨多级 → Provide/Consume页面级共享状态 ├── 父子 → Prop/Link └── 本组件 → State九、总结Provide/Consume 是解决跨级组件通信的利器配合 AppStorage 和 LocalStorage可以应对各种状态管理场景。在徒步迹 App 中我们使用 Provide/Consume 管理登录状态和主题模式后续还会用于轨迹记录的实时数据共享。下一篇文章将学习 Watch 和 ObjectLink 装饰器实现更精细的状态监听。下一篇预告鸿蒙原生开发手记徒步迹 - Watch 与 ObjectLink 深入理解