适用版本 :HarmonyOS 6.1(API 12)及以上 验证环境 :Pura 90 Pro 模拟器(HarmonyOS 6.1.1,API 24) 关键概念 :
@State、@Prop、@Link、@Watch、单向数据流、双向绑定
前言
ArkUI 的状态管理基于响应式模型:状态变量变化时,UI 自动重新渲染关联的组件树。四个核心装饰器各有明确的数据流方向:@State(私有)→ @Prop(单向)→ @Link(双向),@Watch 负责观测变化并触发副作用。
一、@State --- 组件私有状态
typescript
@Entry
@Component
struct CounterPage {
@State count: number = 0 // 私有,只有本组件可读写
build() {
Column({ space: 12 }) {
Text(`count = ${this.count}`)
.fontSize(28).fontWeight(FontWeight.Bold)
Row({ space: 12 }) {
Button('-').onClick(() => { this.count-- })
Button('+').onClick(() => { this.count++ })
}
}
}
}
规则:
@State变量变化 → ArkUI 自动重新渲染依赖它的 UI 区域- 外部组件不能 直接读写
@State变量
二、@Prop --- 父传子(单向)
typescript
@Component
struct ChildDisplay {
@Prop count: number = 0 // 父传来的副本,子不能写回父
build() {
Text(`子组件显示: ${this.count}`).fontColor('#666')
}
}
// 父组件使用
ChildDisplay({ count: this.count }) // 父 count 变 → 子自动刷新
规则:
- 父
@State变化 → 子@Prop自动同步 - 子组件修改
@Prop→ 只改子组件自己的副本,不影响父
三、@Link --- 双向绑定
typescript
@Component
struct SharedCounter {
@Link sharedCount: number // 不设默认值,从父引用
build() {
Column({ space: 8 }) {
Text(`@Link sharedCount = ${this.sharedCount}`)
Button('子组件修改 @Link +1')
.onClick(() => { this.sharedCount++ }) // 同步回父!
}
}
}
// 父组件
@State sharedCount: number = 0
// 使用时传 $(引用符号)
SharedCounter({ sharedCount: $sharedCount })
规则:
@Link不设默认值,必须从父组件接收- 子修改
@Link→ 立即反映到父组件的@State,父 UI 同步刷新
四、@Watch --- 状态变化监听
typescript
@Entry
@Component
struct WatchDemo {
@Watch('onQueryChange') // watchTarget 变化时调用 onQueryChange
@State watchTarget: string = ''
@State log: string[] = []
onQueryChange(): void {
// 副作用:触发搜索、请求 API、发出事件等
this.log = [...this.log.slice(-4), `变化 → "${this.watchTarget}"`]
}
build() {
Column() {
TextInput({ placeholder: '输入触发 @Watch' })
.onSubmit(() => { this.watchTarget = this.inputVal })
ForEach(this.log, (l: string) => {
Text(l).fontColor('#9b59b6')
})
}
}
}
规则:
@Watch('方法名')声明在状态变量前,当该变量变化时调用对应方法- 回调方法不接受参数(用
this.xxx读取新旧值) - 适合触发 API 请求、日志记录等副作用
五、四者对比
| 装饰器 | 数据流向 | 修改权 | 适用场景 |
|---|---|---|---|
@State |
内部 | 只有自己 | 组件私有计数器、开关、表单状态 |
@Prop |
父→子 | 子仅本地 | 展示父数据,子不需要回写 |
@Link |
父↔子 | 双方均可 | 子组件需要修改父状态(如弹窗关闭) |
@Watch |
观察任意 @State | 无(只监听) | 状态变化时触发副作用 |
模拟器运行截图
初始状态

交互后状态
点击「+」按钮增加计数、子组件修改 @Link,以及输入内容触发 @Watch 后的显示状态。

常见问题
Q:为什么修改 @State 对象的属性(如 this.user.name = 'xxx')没有触发 UI 刷新? A:ArkTS 的响应式检测粒度是赋值,而不是属性修改。要触发刷新,需要整体替换对象:
typescript
// ❌ 不触发刷新
this.user.name = 'xxx'
// ✅ 触发刷新(整体替换)
const updated = new User()
updated.name = 'xxx'
updated.age = this.user.age
this.user = updated
Q:@Prop 可以是数组吗? A:可以。@Prop list: string[] = [] 有效,但同样遵循单向规则:子组件修改数组内容不会回写父组件。
Q:@Watch 的回调里可以再修改被 watch 的变量吗? A:可以,但要避免无限循环(修改触发回调,回调再修改,再触发回调...)。通常在回调内加条件判断确保幂等。
上一篇:ArkUI 布局系统 下一篇:@Provide/@Consume 跨组件通信