鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信

掌握跨级组件通信,构建灵活可复用的组件体系


一、前言

在复杂应用中,经常出现祖先组件需要向后代组件传递数据的场景。如果逐层通过 @Prop 传递,会导致"属性逐层传递"的问题(prop drilling),代码冗长且难以维护。

ArkUI 提供了 @Provide/@Consume 装饰器对,实现跨级组件通信,无需中间组件参与。


二、@Provide/@Consume 原理

2.1 基本概念

@Provide 祖先组件 │ │ (自动传递) │ v @Consume 后代组件 1 @Consume 后代组件 2
  • @Provide:在祖先组件中定义,提供数据
  • @Consume:在后代组件中声明,自动获取祖先的 Provide 数据

2.2 基础用法

// 祖先组件 - 提供数据@Componentstruct AppRoot{@Provide('isLoggedIn')isLoggedIn:boolean=false;@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:number=0;// 变量名作为标识build(){Descendant();}}@Componentstruct Descendant{@ConsumestepCount:number;// 自动匹配同名变量// 等价于 @Consume('stepCount') stepCount: number;build(){Text(`步数:${this.stepCount}`);}}

三、@Provide/@Consume vs @Prop/@Link

特性@Prop/@Link@Provide/@Consume
传递层级父子之间任意层级
中间组件需要逐层传递无需参与
使用场景直接父子跨级祖先→后代
性能较好稍差(需查找)
可读性显式传递隐式传递

选择建议

  • 父子组件:用 @State/@Prop/@Link
  • 跨 2 层以上:用 @Provide/@Consume
  • 全局状态:用 AppStorage

四、实战:徒步迹全局登录状态

在徒步迹 App 中,登录状态需要在多个页面间共享:

// AppRoot - 应用根组件@Entry@Componentstruct AppRoot{@Provide('isLogged')isLogged:boolean=false;@Provide('currentUser')currentUser:User|null=null;@Provide('themeMode')themeMode:string='light';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.isLogged=true;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.isLogged=false;this.currentUser=null;});}}}

五、多个 Provide/Consume 的协作

// 追踪页 - 提供多个状态@Componentstruct TrackingSection{@Provide('status')status:string='idle';@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.status='recording';});}}// 统计显示 - 读取状态@Componentstruct StatsDisplay{@Consume('trackData')trackData:TrackData;build(){Text(`距离:${trackData.distance.toFixed(2)}km`);}}

六、AppStorage - 应用级全局存储

除了 @Provide/@Consume,ArkUI 还提供了 AppStorage 用于应用级状态管理:

// 1. 在 Ability 中初始化exportdefaultclassEntryAbilityextendsUIAbility{onCreate():void{AppStorage.setOrCreate('token','');AppStorage.setOrCreate('userId',0);AppStorage.setOrCreate('stepGoal',10000);}}// 2. 在组件中使用@Entry@Componentstruct HomePage{@StorageLink('token')token:string='';@StorageProp('stepGoal')stepGoal:number=10000;build(){Text(`目标步数:${this.stepGoal}`);}}
API说明
@StorageLink(key)双向绑定,组件修改同步到 AppStorage
@StorageProp(key)单向绑定,组件只读
AppStorage.set()设置值
AppStorage.get<T>(key)获取值
AppStorage.setOrCreate(key)不存在时创建

七、LocalStorage - 页面级共享

LocalStorage 是 Ability 或页面级别的共享存储:

// 创建页面级存储letlocalStorage=newLocalStorage({'pageTitle':'徒步迹','pageType':'home',});// 在页面中使用@Entry(localStorage)@Componentstruct HomePage{@LocalStorageLink('pageTitle')title:string='';build(){Text(this.title);}}

八、状态管理选择指南

应用级全局数据? ├── 是 → AppStorage(token、用户信息、设置) └── 否 → 组件间层级? ├── 跨多级 → @Provide/@Consume(页面级共享状态) ├── 父子 → @Prop/@Link └── 本组件 → @State

九、总结

@Provide/@Consume 是解决跨级组件通信的利器,配合 AppStorage 和 LocalStorage,可以应对各种状态管理场景。在徒步迹 App 中,我们使用 @Provide/@Consume 管理登录状态和主题模式,后续还会用于轨迹记录的实时数据共享。

下一篇文章将学习 @Watch 和 @ObjectLink 装饰器,实现更精细的状态监听。


下一篇预告:鸿蒙原生开发手记:徒步迹 - @Watch 与 @ObjectLink 深入理解