HarmonyOS鸿蒙Next中ArkTS的@Observed和@ObjectLink在深层嵌套对象更新时,会不会导致不必要的父组件重渲染?
HarmonyOS鸿蒙Next中ArkTS的@Observed和@ObjectLink在深层嵌套对象更新时,会不会导致不必要的父组件重渲染?
我的数据结构是 { user: { profile: { avatar: string } } },只改 avatar,但整个用户卡片都刷新了。如何精准更新?
@Observed在父组件用,@ObjectLink在子组件用。avatar改变了,应该只有子组件更新了。父组件不会更新的。你是这样用的么
更多关于HarmonyOS鸿蒙Next中ArkTS的@Observed和@ObjectLink在深层嵌套对象更新时,会不会导致不必要的父组件重渲染?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
使用@Track装饰器可以避免冗余刷新。
@Track应用于class对象的属性级更新。@Track装饰的属性变化时,只会触发该属性关联的UI更新。
限制:如果class类中使用了@Track装饰器,则未被@Track装饰器装饰的属性不能在UI中使用,如果使用,会发生运行时报错。
import { hilog } from '@kit.PerformanceAnalysisKit';
const DOMAIN_NUMBER: number = 0XFF00;
const TAG: string = '[Sample_StateTrack]';
class LogTrack {
[@Track](/user/Track) public str1: string;
[@Track](/user/Track) public str2: string;
constructor(str1: string) {
this.str1 = str1;
this.str2 = 'World';
}
}
class LogNotTrack {
public str1: string;
public str2: string;
constructor(str1: string) {
this.str1 = str1;
this.str2 = 'World';
}
}
@Entry
@Component
struct AddLog {
@State logTrack: LogTrack = new LogTrack('Hello');
@State logNotTrack: LogNotTrack = new LogNotTrack('Hello');
isRender(index: number) {
hilog.info(DOMAIN_NUMBER, TAG, `Text ${index} is rendered`);
return 50;
}
build() {
Row() {
Column() {
Text(this.logTrack.str1) // Text1
.id('str1')
.fontSize(this.isRender(1))
.fontWeight(FontWeight.Bold)
Text(this.logTrack.str2) // Text2
.fontSize(this.isRender(2))
.fontWeight(FontWeight.Bold)
Button('change logTrack.str1')
.id('str2')
.onClick(() => {
this.logTrack.str1 = 'Bye';
})
Text(this.logNotTrack.str1) // Text3
.fontSize(this.isRender(3))
.fontWeight(FontWeight.Bold)
Text(this.logNotTrack.str2) // Text4
.fontSize(this.isRender(4))
.fontWeight(FontWeight.Bold)
Button('change logNotTrack.str1')
.onClick(() => {
this.logNotTrack.str1 = 'Bye';
})
}
.width('100%')
}
.height('100%')
}
}
在上面的示例中:
本身就会刷新吧,而且不会有啥太大影响
没碰到过
在HarmonyOS鸿蒙Next中,ArkTS的@Observed和@ObjectLink用于深层嵌套对象更新时,不会直接导致不必要的父组件重渲染。@ObjectLink装饰器会创建对@Observed装饰的对象的内部属性的双向数据绑定。当被观察的嵌套对象的属性发生变化时,只有使用了该特定@ObjectLink变量的组件会重新渲染,而父组件不会因此触发不必要的重渲染。
在HarmonyOS Next的ArkUI中,@Observed和@ObjectLink的设计初衷是实现对嵌套对象属性的精细观察和响应。根据你的描述,当只修改深层属性user.profile.avatar时,整个用户卡片发生重渲染,这通常意味着数据观察的粒度设置不够精确。
核心问题在于:@Observed装饰的类,其所有属性都被视为可观察的。在你的嵌套结构{ user: { profile: { avatar: string } } }中,如果user或profile本身被@Observed装饰,那么对avatar的修改会触发从user或profile开始的属性变更通知,从而导致依赖它们的组件(整个用户卡片)进行更新检查。
要实现精准更新,关键在于让观察点尽可能接近实际发生变化的属性。建议方案如下:
-
精细化装饰:确保只有真正需要被观察的类才使用
@Observed。对于你的数据结构:- 将
profile类用@Observed装饰。 - 在
user类中,将profile成员变量用@ObjectLink装饰(或使用@Observed装饰user类,但profile用@ObjectLink建立关联)。 - 在组件中,只
@ObjectLink链接到具体的profile对象,而不是整个user对象。
- 将
-
代码结构示例:
@Observed class Profile { avatar: string = ''; // ... 其他属性 } class User { // User类可以不用@Observed profile: Profile = new Profile(); // 或者用@ObjectLink装饰,如果User也是@Observed } @Component struct UserCard { @ObjectLink profile: Profile; // 只观察profile build() { // 组件只使用this.profile.avatar // 当avatar更新时,只有依赖此@ObjectLink profile的组件会重新渲染 } } -
使用
@Track装饰器:如果希望在一个@Observed类内部,只对某些特定属性的修改触发UI更新,可以使用@Track装饰该属性。这样,即使类被@Observed装饰,也只有被@Track装饰的属性变化会通知UI更新。但这更适用于类内部多个独立可观察属性的场景。
总结:要避免不必要的父组件重渲染,应确保@ObjectLink指向的是最内层、变化最频繁的@Observed对象(在你的案例中是profile),而不是外层的大对象(user)。通过将观察点下沉,可以最大限度地缩小UI更新的范围。

