鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信
·
鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信
掌握跨级组件通信,构建灵活可复用的组件体系
一、前言
在复杂应用中,经常出现祖先组件需要向后代组件传递数据的场景。如果逐层通过 @Prop 传递,会导致"属性逐层传递"的问题(prop drilling),代码冗长且难以维护。
ArkUI 提供了 @Provide/@Consume 装饰器对,实现跨级组件通信,无需中间组件参与。
二、@Provide/@Consume 原理
2.1 基本概念
@Provide 祖先组件
│
│ (自动传递)
│
v
@Consume 后代组件 1 @Consume 后代组件 2
@Provide:在祖先组件中定义,提供数据@Consume:在后代组件中声明,自动获取祖先的 Provide 数据
2.2 基础用法
// 祖先组件 - 提供数据
@Component
struct AppRoot {
@Provide('isLoggedIn') isLoggedIn: boolean = false;
@Provide('userName') userName: string = '';
build() {
Column() {
// 中间组件(不需要传递任何数据)
MainContent();
}
}
}
// 中间组件 - 不接触数据
@Component
struct MainContent {
build() {
Column() {
UserProfile();
}
}
}
// 后代组件 - 消费数据
@Component
struct 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 使用变量名自动匹配:
@Component
struct Ancestor {
@Provide stepCount: number = 0; // 变量名作为标识
build() {
Descendant();
}
}
@Component
struct Descendant {
@Consume stepCount: 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
@Component
struct 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 登录页面使用
@Component
struct 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 个人中心页面使用
@Component
struct 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 的协作
// 追踪页 - 提供多个状态
@Component
struct TrackingSection {
@Provide('status') status: string = 'idle';
@Provide('trackData') trackData: TrackData = {
duration: 0,
distance: 0,
points: [],
};
build() {
Column() {
ControlPanel();
StatsDisplay();
MapView();
}
}
}
// 控制面板 - 修改状态
@Component
struct ControlPanel {
@Consume('status') status: string;
@Consume('trackData') trackData: TrackData;
build() {
Button('开始')
.onClick(() => {
this.status = 'recording';
});
}
}
// 统计显示 - 读取状态
@Component
struct StatsDisplay {
@Consume('trackData') trackData: TrackData;
build() {
Text(`距离: ${trackData.distance.toFixed(2)}km`);
}
}
六、AppStorage - 应用级全局存储
除了 @Provide/@Consume,ArkUI 还提供了 AppStorage 用于应用级状态管理:
// 1. 在 Ability 中初始化
export default class EntryAbility extends UIAbility {
onCreate(): void {
AppStorage.setOrCreate('token', '');
AppStorage.setOrCreate('userId', 0);
AppStorage.setOrCreate('stepGoal', 10000);
}
}
// 2. 在组件中使用
@Entry
@Component
struct 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 或页面级别的共享存储:
// 创建页面级存储
let localStorage = new LocalStorage({
'pageTitle': '徒步迹',
'pageType': 'home',
});
// 在页面中使用
@Entry(localStorage)
@Component
struct 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 深入理解
更多推荐




所有评论(0)