鸿蒙原生开发手记:徒步迹 - @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 深入理解
