用 ArkTS 的 @Observed 与 @ObjectLink 管理鸿蒙应用的跨页面共享状态

举报
yd_276656611 发表于 2026/11/11 09:57:00 2026/11/11
【摘要】 本文以单词打卡应用为例,介绍 ArkTS 中 @Observed 与 @ObjectLink 的分工与跨页面共享写法,并总结三个常见坑,帮助开发者让多页面共享同一份可变状态。

在鸿蒙应用开发中,页面之间共享一份可变状态是最常见的需求之一。比如一个单词打卡应用:首页要显示今日已背单词数,单词详情页要修改掌握程度,统计页要汇总本周打卡情况,三处读写的其实是同一份数据。如果每个页面各自维护一份状态,数据很快就会互相打架。本文结合一个小型实践,聊聊 ArkTS 中 @Observed 与 @ObjectLink 这对组合的正确用法。

一、问题从哪里来

ArkTS 的 @State 只能管理当前组件内部的状态,子组件想修改父组件的数据,一般用 @Link。但 @Link 有一个限制:它只能同步一层数据。当状态是一个对象、且要修改的是对象内部的属性时,@Link 就无能为力了。更麻烦的是页面跳转:用 router.pushUri 跳到新页面后,@Link 链路断开,新页面拿到的是数据的快照而不是引用,改了也不会回写。

二、@Observed 与 @ObjectLink 的分工

@Observed 修饰一个类,表示这个类的实例是可观察的,实例内部属性的变化可以被 UI 感知。@ObjectLink 则用在子组件或子页面中,接收一个 @Observed 类型的对象,并与之建立引用关系。两者分工很明确:@Observed 负责让数据可观察,@ObjectLink 负责让多处共享同一份引用。

@Observed
class WordBook {
  todayCount: number = 0;
  mastered: string[] = [];
  markMastered(word: string) {
    if (!this.mastered.includes(word)) {
      this.mastered.push(word);
      this.todayCount++;
    }
  }
}

注意 markMastered 把“去重”和“计数”收敛到数据类内部,而不是散落在各个页面里。这样无论多少页面共享这份数据,业务规则都只有一份。

三、跨页面共享的完整写法

入口页面持有这份数据的唯一实例,子组件和子页面只持有引用。

@Entry
@Component
struct HomePage {
  @State book: WordBook = new WordBook();
  build() {
    Column() {
      Text(`今日已背 ${this.book.todayCount} 个单词`)
      WordCard({ book: this.book })
    }
  }
}

@Component
struct WordCard {
  @ObjectLink book: WordBook;
  build() {
    Button('掌握了').onClick(() => {
      this.book.markMastered('abandon');
    })
  }
}

跨页面时,把同一个 book 实例通过路由参数的共享对象或全局单例传递过去,子页面同样用 @ObjectLink 接收。点击“掌握了”之后,首页的计数会立刻刷新,统计页读取到的也是更新后的结果,因为它们指向的是同一个 WordBook 实例。

四、容易踩的三个坑

第一,只给外层加 @State,不给数据类加 @Observed。此时对象引用变化能刷新,对象内部属性变化却不会刷新,表现为改了数据界面不动。

第二,在子组件里给 @ObjectLink 修饰的变量重新赋值。@ObjectLink 建立的是引用关系,重新赋值会断开与源数据的链接,之后再改就互不影响了。正确做法是只修改对象的属性,或调用对象的方法。

第三,在不需要共享的场景滥用这套组合。如果状态只在单个组件内部使用,直接用 @State 就够了。共享状态的层级越少,数据流向越清晰,出了问题也越容易定位。

五、小结

@Observed 让对象内部的变化可被观察,@ObjectLink 让多个组件和页面共享同一份引用。把状态的唯一来源放在一处、把修改规则收进数据类内部,页面之间就不再需要层层透传回调。下一篇文章,我会继续用这个单词打卡应用为例,聊聊如何用 Preferences 把这份共享状态持久化到本地,让打卡记录在应用重启后依然存在。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。