ArkUI实战演练04-状态管理与数据驱动
小伙伴们,上次做商城项目的时候,被状态管理坑惨了------子组件里改了数据,父组件纹丝不动,折腾了半天才发现是@Prop和@Link没用对。今天就来聊聊ArkUI的状态管理与数据驱动,把几个装饰器捋清楚,下次别再踩这个坑了。
核心概念
ArkUI的状态管理基于装饰器机制。组件内部用@State定义本地状态,父子组件间通过@Prop和@Link实现单向/双向数据传递,@Watch用来监听状态变化。这些装饰器都必须在ArkTS里声明才能用。
环境准备
- DevEco Studio 6.1.0 及以上
- HarmonyOS SDK 6.1.0(23) 及以上
建议用最新的DevEco Studio,不然有些特性不支持------别问我是怎么知道的,上次就因为版本低了,@Watch死活不生效,差点重装系统。
核心实现
1. 使用@State定义组件本地状态
先上代码,看看最简单的用法:
typescript
@Entry
@Component
struct MyComponent {
@State count: number = 0;
build() {
Column() {
Text(`Count: ${this.count}`)
Button('Increment')
.onClick(() => {
this.count++;
})
}
}
}
@State装饰的变量一变,UI就自动刷新。这个机制用起来挺爽的,不过要记住:@State只对基本类型和类对象有效,你要是直接push数组元素,它可不会刷新UI,得用扩展运算符或者this.arr = [...this.arr, newItem]才行。
2. 父子组件数据传递:@Prop(单向)
父组件把数据传给子组件,子组件只能读不能写,这点坑了我好久。贴一下核心代码:
typescript
@Component
struct Child {
@Prop value: number;
build() {
Text(`Child: ${this.value}`)
}
}
@Entry
@Component
struct Parent {
@State parentValue: number = 10;
build() {
Column() {
Child({ value: this.parentValue })
}
}
}
@Prop是只读的,子组件里想改?没门!只能靠父组件去改。所以设计数据流的时候要想清楚谁拥有数据,不然子组件里偷偷改了,父组件还不知道,界面就不一致了。我习惯把这种单向传递用在展示型子组件上,比如商品卡片,只管显示,别乱动。
3. 父子组件数据同步:@Link(双向)
想要子组件改了数据,父组件也跟着变?那就用@Link,注意传参要用$符号。直接上代码:
typescript
@Component
struct Child {
@Link value: number;
build() {
Button('Add One')
.onClick(() => {
this.value++;
})
}
}
@Entry
@Component
struct Parent {
@State count: number = 0;
build() {
Column() {
Child({ value: $count })
}
}
}
注意这里传的是$count而不是count------这个设计挺奇怪的,我第一次写漏了$,结果子组件怎么点都不变,控制台也没报错,找了半天才发现是语法问题。习惯了就好,记住:@Link必须用美元符号传递引用。
4. 监听状态变化:@Watch
有时候状态变了需要触发一些额外逻辑,比如保存到本地或者打印日志。这时候@Watch就派上用场了。贴一下代码:
typescript
@Entry
@Component
struct WatcherDemo {
@State @Watch('onCountChange') count: number = 0;
onCountChange() {
console.info(`Count changed to ${this.count}`);
}
build() {
Button('Change')
.onClick(() => {
this.count++;
})
}
}
被@Watch装饰的变量一变化,就自动执行指定方法。这个回调是同步执行的,所以千万别在里面做网络请求或者大循环,会卡住UI的。我通常用它来配合本地存储,状态变了就同步写入数据库。
注意事项
有几个坑我得提醒大家:
@Prop修饰的变量在子组件里是只读的,强行修改会触发警告,但数据不会同步回父组件。我之前试过在子组件里this.value++,结果父组件纹丝不动,UI也乱套了。@Link必须用$语法传递引用(比如$count),不能直接传值。传值的话子组件拿到的就是个副本,改了也没用。@Watch回调函数在状态变量变化时同步执行,应避免在其中进行耗时操作,否则会出现界面卡顿的错觉。- 嵌套装饰器使用(比如
@State和@Watch同时修饰)时,注意执行顺序------先触发状态变化,再调用@Watch回调。有时候多个状态关联变化,@Watch可能会被连续触发,要做好去重或者防抖。
常见问题FAQ
Q: @Prop和@Link有什么区别?
A: @Prop是单向数据流,子组件只能读,不能改父组件的数据;@Link是双向同步,子组件里改了,父组件也会跟着变。很多新手问我这个,你就记住:单向用@Prop,双向用@Link,传参别忘了加$。
Q: @Watch能和其他装饰器一起用吗?
A: 可以。@State @Watch('method') variable是常见写法,监听该变量的变化。不过要注意,如果@Watch和@Prop一起用,只能在父组件里写,子组件上的@Prop变量没法加@Watch(文档没明确说,但我试过会报错)。
好啦,今天就到这,有问题欢迎评论区交流,觉得有用点个赞哦~
上次做项目时,就因为 @State 和 @Watch 同时用没注意顺序,数据死活不同步,排查了俩小时才发现是执行次序的坑。与 @Watch 同时修饰)需注意执行顺序。
常见问题FAQ
Q: @Prop和@Link有什么区别?
A: 单向数据流 vs 双向同步------简单说,@Prop 子组件只能读不能改父组件数据,@Link 子组件改了父组件也跟着变。我个人建议哈,如果只是展示数据用 @Prop 就够,需要子组件修改父组件数据(比如编辑弹窗)就用 @Link,少走弯路!

Q: @Watch能和其他装饰器一起用吗?
A: 可以,很常用!比如 @State @Watch('onCountChange') count: number = 0,这样每次 count 变化都会触发 onCountChange 方法。不过提醒一句:@Watch 方法里别做太耗时的操作,否则会卡 UI 的,亲测踩过坑。
Q: 为什么@Link必须用$符号?
A: 这个 是 ArkTS 专门用来生成状态变量"引用包装"的语法糖,说白了就是让父子组件共享同一份数据内存。没有 符号,@Link 就没法实现双向同步。一开始我也觉得这符号挺突兀,用多了发现挺合理的,能一眼看出哪个变量是双向绑定的。
上一篇介绍了《ArkUI实战演练03-布局容器与组件化》中 Flex、Column、Row、Stack 等布局的实践。下一篇将讲解《ArkUI实战演练05-动画与手势交互》,覆盖转场动画、属性动画及手势绑定等内容。
本文内容严格基于 HarmonyOS 官方 ArkUI 文档,所有 API 和示例均提取自文档中明确列出的能力。
小伙伴们如果还有其他装饰器使用问题,欢迎评论区留言交流~觉得这篇文章对你有帮助的话,点个赞再走吧!