HarmonyOS 鸿蒙Next中使用 @Observed 与 @ObjectLink 实现对象深层响应式更新

HarmonyOS 鸿蒙Next中使用 @Observed@ObjectLink 实现对象深层响应式更新 当 @State 绑定的是一个普通 class 对象时,我们直接修改对象内部属性不会触发 UI 刷新。那我们就需要通过 @Observed + @ObjectLink,来让对象内部属性变更也能被感知,实现更加好的响应式更新体验。

3 回复

问题

我们在声明式 UI 框架中,响应式更新主要依赖于状态变量的变更通知这种机制。但是,当 @State 绑定的是一个普通 JavaScript 对象实例时,框架默认只监听对象引用的变化,而不会追踪其内部属性的修改。这意味着直接赋值虽然改变了数据,但 UI 并不会刷新,导致视图与状态不一致,那我们如何解决呢?

思路

因为在HarmonyOS 6 中引入了 @Observed@ObjectLink ,所以我们通过这2个组件来进行方案组合:

首先,通过 @Observed 装饰器标记目标实例,使得对应的实例具备属性变更可观察性——ArkTS 编译器会为其实例生成代理(Proxy)包装,以此来进行拦截属性读写操作;

其次,在父组件中使用 @State 声明该类的实例,确保其作为状态源;

最后,在子组件中通过 @ObjectLink 接收该对象,这里需要注意,不是使用 @Prop了,@ObjectLink 会自动订阅该对象内部属性的变化,并在任一属性更新时触发子组件的重新构建。

实现步骤:

步骤 1:用 [@Observed](/user/Observed) 装饰需要响应的对象类

[@Observed](/user/Observed)
export class User {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

步骤 2:在父组件中用 [@State](/user/State) 声明该对象实例

@Entry
@Component
struct UserProfile {
  [@State](/user/State) user: User = new User('Alice', 25);
  // ...
}

步骤 3:子组件通过 [@ObjectLink](/user/ObjectLink) 接收对象

@Component
struct UserInfoCard {
  [@ObjectLink](/user/ObjectLink) user: User; // ← 关键:必须用 [@ObjectLink](/user/ObjectLink)

  build() {
    Column() {
      Text(`姓名: ${this.user.name}`)
      Text(`年龄: ${this.user.age}`)
    }
  }
}

步骤 4:直接修改对象属性即可自动更新 UI

// 在父组件中
Button('改名')
  .onClick(() => {
    this.user.name = 'Bob'; 
  })

完整示例代码:

[@Observed](/user/Observed)
export class User {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

@Component
struct UserInfoCard {
  [@ObjectLink](/user/ObjectLink) user: User;

  build() {
    Column({ space: 8 }) {
      Text(`姓名: ${this.user.name}`)
        .fontSize(18)
      Text(`年龄: ${this.user.age}`)
        .fontColor(Color.Gray)
    }
    .padding(15)
    .backgroundColor('#F9F9F9')
    .borderRadius(12)
  }
}

@Entry
@Component
struct ObservedDemo {
  [@State](/user/State) user: User = new User('Alice', 25);

  build() {
    Column({ space: 20 }) {
      Text('[@Observed](/user/Observed) 对象响应式示例')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)

      UserInfoCard({ user: this.user })

      Row({ space: 10 }) {
        Button('改名 → Bob')
          .onClick(() => {
            this.user.name = 'Bob';
          })
        Button('+1岁')
          .onClick(() => {
            this.user.age += 1;
          })
      }
    }
    .padding(30)
    .width('100%')
    .height('100%')
  }
}

更多关于HarmonyOS 鸿蒙Next中使用 @Observed 与 @ObjectLink 实现对象深层响应式更新的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,@Observed@ObjectLink用于实现嵌套对象的响应式更新。@Observed装饰类,使其属性变化可被观察到;@ObjectLink装饰变量,用于接收@Observed类的实例,并建立双向同步。当@Observed对象的深层属性变更时,使用@ObjectLink的UI组件会自动更新。这解决了嵌套对象属性变更无法触发UI刷新的问题。

在 HarmonyOS Next 中,[@Observed](/user/Observed)[@ObjectLink](/user/ObjectLink) 是用于实现嵌套对象或类属性响应式更新的关键装饰器,解决了 @State 无法直接监听对象内部属性变化的问题。

核心机制:

  1. @Observed:装饰一个类,使其成为可观察的。系统会为这个类生成一个代理包装类,从而能够监听其内部属性的变更。
  2. @ObjectLink:装饰一个被 [@Observed](/user/Observed) 修饰的类的实例变量。它接受一个来自父组件(通常是 @State@Link 修饰的 [@Observed](/user/Observed) 类实例)的“引用”,并建立起响应式关联。

工作流程:

  • [@Observed](/user/Observed) 类的实例属性被修改时,代理包装类会检测到变更。
  • 与这个实例通过 [@ObjectLink](/user/ObjectLink) 建立关联的组件,会收到属性变更的通知。
  • 组件使用新的属性值重新渲染对应的 UI 部分。

典型代码结构:

// 1. 使用 [@Observed](/user/Observed) 装饰类
[@Observed](/user/Observed)
class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

@Entry
@Component
struct ParentComponent {
  // 2. 父组件使用 @State 或 @Link 装饰一个 [@Observed](/user/Observed) 类的实例
  @State person: Person = new Person('Alice', 25);

  build() {
    Column() {
      // 3. 将实例传递给子组件
      ChildComponent({ person: this.person })
      Button('修改年龄')
        .onClick(() => {
          // 4. 修改对象内部属性,触发UI更新
          this.person.age += 1;
        })
    }
  }
}

@Component
struct ChildComponent {
  // 5. 子组件使用 [@ObjectLink](/user/ObjectLink) 接收并建立响应式链接
  [@ObjectLink](/user/ObjectLink) person: Person;

  build() {
    Text(`姓名: ${this.person.name}, 年龄: ${this.person.age}`)
  }
}

关键点:

  • [@ObjectLink](/user/ObjectLink) 变量必须是 [@Observed](/user/Observed) 类的实例,且通常从父组件初始化。
  • 它建立的是对父组件中对应状态“引用”的同步,修改 [@ObjectLink](/user/ObjectLink) 变量的属性会直接更新父组件源状态。
  • @Link 不同,[@ObjectLink](/user/ObjectLink) 专门用于解构 [@Observed](/user/Observed) 类的响应式属性更新,避免不必要的整个对象重新渲染。

这种模式非常适合管理复杂的对象状态,确保深层次属性变更能精准触发UI更新,提升应用性能。

回到顶部