HarmonyOS 鸿蒙Next中使用 @Observed 与 @ObjectLink 实现对象深层响应式更新
HarmonyOS 鸿蒙Next中使用 @Observed 与 @ObjectLink 实现对象深层响应式更新 当 @State 绑定的是一个普通 class 对象时,我们直接修改对象内部属性不会触发 UI 刷新。那我们就需要通过 @Observed + @ObjectLink,来让对象内部属性变更也能被感知,实现更加好的响应式更新体验。
问题
我们在声明式 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 无法直接监听对象内部属性变化的问题。
核心机制:
- @Observed:装饰一个类,使其成为可观察的。系统会为这个类生成一个代理包装类,从而能够监听其内部属性的变更。
- @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更新,提升应用性能。

