HarmonyOS 鸿蒙Next中使用 Provide/Consume + @ObjectLink 多层级传递数据的问题
HarmonyOS 鸿蒙Next中使用 Provide/Consume + @ObjectLink 多层级传递数据的问题 代码如下所示,比如我在父组件上有一个Array叫petInformationList,通过遍历这个Array,传递petInformation,构建子组件FirstLevelPage,子组件后续又有子组件也需要这个petInformation,我通过这个@ObjectLink 来装饰这个petInformation。然后某一个层级的petInformation改变之后,会通过这个Provide/Consume来改变petInformationList。我想问的是,如果这个petInformationList更改之后,是否会通知被@ObjectLink装饰的petInformation更改重新渲染。比如说我在第五层级页面FiveLevelPage更改了被Provide/Consume装饰的petInformationList,那么当前页面,也就是FiveLevelPage是否会被通知@ObjectLink petInformation: PetInformationModel更改然后重新渲染,已经前面的1、2、3、4页面或者6、7、8页面是否也会跟着更改,然后重新渲染?不知道我说的是否理解
// 顶级组件 @Entry @Component struct ParentPage { @Provide petInformationList: Array<PetInformationModel> = []
build() { Column() { ForEach(this.petInformationList, (item: PetInformationModel) => { FirstLevelPage({ petInformation: item }) }) } } }
// 多级页面都使用 @ObjectLink @Component struct FirstLevelPage { @ObjectLink petInformation: PetInformationModel
build() { Column() { Text(this.petInformation.name) SecondLevelPage({ petInformation: this.petInformation }) } } }
@Component struct SecondLevelPage { @ObjectLink petInformation: PetInformationModel
build() { Column() { Text(this.petInformation.name) ThirdLevelPage({ petInformation: this.petInformation }) } } }
更多关于HarmonyOS 鸿蒙Next中使用 Provide/Consume + @ObjectLink 多层级传递数据的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
【背景知识】
[@Provide和@Consume装饰器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-provide-and-consume),应用于组件与其后代组件的双向数据同步。在祖先组件中通过@Provide装饰变量,以此给所有后代组件提供状态变量,后代组件中通过@Consume装饰的变量来接收这些状态变量,实现跨组件状态共享。
在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于数据模型多层嵌套的场景,[@Observed/@ObjectLink装饰器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-observed-and-objectlink)配套使用可以弥补@Provide/@Consume装饰器仅能观察一层的能力限制。
【解决方案】
@Observed和@ObjectLink作用于父子组件间复杂对象的深层嵌套观察,所以当使用同一个@Provide修饰的对象,在其他层级使用@ObjectLink的时候数据发生变化也会发生变化并重新渲染的。
// 顶级组件
[@Observed](/user/Observed)
class PetInformationModel {
name: string = ''
constructor(name: string) {
this.name = name
}
}
@Entry
@Component
struct ParentPage {
[@Provide](/user/Provide) petInformationList: Array<PetInformationModel> = [new PetInformationModel('xxxx')]
build() {
Column() {
ForEach(this.petInformationList, (item: PetInformationModel) => {
FirstLevelPage({
petInformation: item
})
})
Button('改变数组').onClick(()=>{
this.petInformationList[0].name='test'
})
}
}
}
// 多级页面都使用 [@ObjectLink](/user/ObjectLink)
@Component
struct FirstLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test1'
})
SecondLevelPage({
petInformation: this.petInformation
})
}
}
}
@Component
struct SecondLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test2'
})
ThirdLevelPage({
petInformation: this.petInformation
})
}
}
}
@Component
struct ThirdLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test3'
})
FourLevelPage({
petInformation: this.petInformation
})
}
}
}
@Component
struct FourLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test4'
})
FiveLevelPage({
petInformation: this.petInformation
})
}
}
}
@Component
struct FiveLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test5'
})
SixLevelPage({
petInformation: this.petInformation
})
}
}
}
@Component
struct SixLevelPage {
[@ObjectLink](/user/ObjectLink) petInformation: PetInformationModel
build() {
Column() {
Text(this.petInformation.name).onClick(() => {
this.petInformation.name = 'test6'
})
}
}
}
更多关于HarmonyOS 鸿蒙Next中使用 Provide/Consume + @ObjectLink 多层级传递数据的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
import 'reflect-metadata';
import { Expose } from 'class-transformer';
export class PetInformationModel {
@Expose()
id: number = 0;
@Expose()
stage: string = '';
@Expose({ name: 'year_count' })
yearCount: number = 0;
我的PetInformationModel是类似下面这样的,如果我不用@Observed装饰,是不是只能通过this.petInformationList = [PetInformationModel] 这种去改变整个petInformationList的方式使得页面重新渲染?
如果我使用@Observed来装饰我PetInformationModel的话,如果PetInformationModel下面的name、weight、age这三个参数在下级页面都有可能单独或者同时发生变化,我应该怎么写constructor函数?constructor函数的作用是什么?
constructor是个构造函数,用于初始化对象实例,这样new对象的时候就可以在new的时候直接new 对象(‘xxx’)这样填充函数了,这样就不需要new出来在在xxx.name='xxx’这样赋值了,这个和页面刷新变化没有关系,@Observed必须配合@ObjectLink使用才能观察到变化,
a页面的itemList和b页面的itemList用的不是同一组数据,b页面的itemList可能包含a页面的itemList,也可能不包含,这样子的话,是不是只能通过回调函数去处理?
是的,不是同一组数据的话就不要用状态变量来处理了,这就相当于两个单独的list了。
下拉刷新,上拉加载,是不是用这两个组件比较好Refresh、WaterFlow。
有没有类似于微信朋友圈图片排列的九宫格实现demo参考一下,
在HarmonyOS Next中,Provide/Consume与@ObjectLink用于跨层级组件数据同步。Provide在父组件声明,提供数据;Consume在子组件引用数据。@ObjectLink装饰的变量接收Provide提供的可观察对象,并建立双向绑定。当Provide数据变更时,所有关联的@ObjectLink变量自动更新。需注意避免循环引用,确保Provide覆盖需要数据共享的组件层级。@ObjectLink仅可观察对象属性变化,若替换整个对象需使用@Consume。
在 HarmonyOS Next 中,@ObjectLink
装饰的变量与 @Provide
/@Consume
机制结合使用时,数据变更的响应是精确且高效的。针对你的问题:
-
当
petInformationList
通过@Provide
更新时,所有直接或间接依赖该数据的@ObjectLink
装饰属性会触发重新渲染。在FiveLevelPage
中修改petInformationList
后:- 当前页面(FiveLevelPage):其
@ObjectLink petInformation
会立即检测到数据变更并重新渲染。 - 上游页面(1~4级):若这些层级的组件通过
@ObjectLink
绑定同一PetInformationModel
对象,且该对象的属性被修改,则它们也会同步更新并重新渲染。 - 下游页面(6~8级):同样通过
@ObjectLink
绑定同一数据对象时,变更会逐层传递,触发重新渲染。
- 当前页面(FiveLevelPage):其
-
关键机制说明:
@ObjectLink
直接跟踪对象引用,当对象的属性被修改(如petInformation.name
变化),所有绑定该对象的组件均会响应。@Provide
/@Consume
负责跨层级数据同步,确保petInformationList
的变更能传递到依赖它的子组件。
-
注意事项:
- 若直接替换整个
petInformationList
数组(而非修改数组内对象属性),需确保@ObjectLink
绑定的对象引用未丢失,否则需通过@Consume
重新获取数据。 - 对象属性的修改会通过 ArkUI 响应式系统自动触发关联组件的更新,无需手动通知。
- 若直接替换整个
总结:你的设计能正确实现多层级数据联动渲染,FiveLevelPage
的修改会通知所有绑定同一数据对象的组件更新。