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

10 回复

【背景知识】

[@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 机制结合使用时,数据变更的响应是精确且高效的。针对你的问题:

  1. petInformationList 通过 @Provide 更新时,所有直接或间接依赖该数据的 @ObjectLink 装饰属性会触发重新渲染。在 FiveLevelPage 中修改 petInformationList 后:

    • 当前页面(FiveLevelPage):其 @ObjectLink petInformation 会立即检测到数据变更并重新渲染。
    • 上游页面(1~4级):若这些层级的组件通过 @ObjectLink 绑定同一 PetInformationModel 对象,且该对象的属性被修改,则它们也会同步更新并重新渲染。
    • 下游页面(6~8级):同样通过 @ObjectLink 绑定同一数据对象时,变更会逐层传递,触发重新渲染。
  2. 关键机制说明

    • @ObjectLink 直接跟踪对象引用,当对象的属性被修改(如 petInformation.name 变化),所有绑定该对象的组件均会响应。
    • @Provide/@Consume 负责跨层级数据同步,确保 petInformationList 的变更能传递到依赖它的子组件。
  3. 注意事项

    • 若直接替换整个 petInformationList 数组(而非修改数组内对象属性),需确保 @ObjectLink 绑定的对象引用未丢失,否则需通过 @Consume 重新获取数据。
    • 对象属性的修改会通过 ArkUI 响应式系统自动触发关联组件的更新,无需手动通知。

总结:你的设计能正确实现多层级数据联动渲染,FiveLevelPage 的修改会通知所有绑定同一数据对象的组件更新。

回到顶部