主题
ArkTS 状态管理三部曲:@State / @Prop / @Link
一、总览对比
| @State | @Prop | @Link | |
|---|---|---|---|
| 响应式 | ✅ 变了刷新 UI | ✅ 变了刷新 UI | ✅ 变了刷新 UI |
| 数据来源 | 自己管自己 | 自己管 / 父传值覆盖 | 必须父传值 |
| 子修改影响父 | — | ❌ 不影响 | ✅ 父跟着变 |
| 父修改影响子 | — | ✅ 覆盖子 | ✅ 子跟着变 |
| 单独存在 | ✅ 正常 | ✅ 像 @State | ❌ 不能单独用 |
| 本质 | 本地状态 | 本地状态 + 可被父覆盖 | 父子共享同一份数据 |
二、@State — 组件内部状态
typescript
@Component
struct MyComp {
@State count: number = 0 // 自己管自己
build() {
Button('+').onClick(() => this.count++) // 变了 → UI 刷新
Text(`${this.count}`)
}
}- 最常用,每个组件的本地状态
- 只有自己能改,外界无法干预
三、@Prop — 父 → 子单向数据流
typescript
// 父组件
@Component
struct Parent {
@State count: number = 0
build() {
Child({ value: this.count }) // 传过去
Button('父+').onClick(() => this.count++)
}
}
// 子组件
@Component
struct Child {
@Prop value: number = 0 // 从父接收,也可以自己管自己
build() {
Text(`${this.value}`)
Button('子+').onClick(() => this.value++) // 子改了,父不变
}
}执行结果:
操作 父 count 子 value
初始 0 0
点 子+ 0 1 ← 子改子的,父不变
点 父+ 1 1 ← 父变了,覆盖子
再点 子+ 1 2 ← 子又自己独立变化两种用法:
| 用法 | 效果 |
|---|---|
@Prop value: number = 0(无父传值) | = @State,自己管自己 |
@Prop value: number = 0(父传值) | 初始从父拿,之后父变覆盖子,子变不影响父 |
四、@Link — 父子双向同步
typescript
// 父组件
@Component
struct Parent {
@State count: number = 0
build() {
Child({ value: $count }) // @Link 必须用 $ 传引用
Button('父+').onClick(() => this.count++)
}
}
// 子组件
@Component
struct Child {
@Link value: number // 注意:不能给默认值,必须从父传
build() {
Text(`${this.value}`)
Button('子+').onClick(() => this.value++) // 子改了,父也跟着变
}
}执行结果:
操作 父 count 子 value
初始 0 0
点 子+ 1 1 ← 双向同步!
点 父+ 2 2 ← 双向同步!与 @Prop 的关键区别:
@Prop @Link
父 ──传值──→ 子 父 ←─共享─→ 子
父变了覆盖子 任何一方变了,对方都跟着变
子变了不影响父五、一句话总结
| 装饰器 | 记法 |
|---|---|
@State | 我的地盘我做主 |
@Prop | 你给我一份拷贝,我改我的不影响你 |
@Link | 咱俩共享同一份,你改我变,我改你变 |
六、完整对照示例
父组件 @State count
├── childProp({ value: count }) ← @Prop:父变覆盖子,子变不影响父
│ 子点 + → 子 +1,父不变
│ 父点 + → 父 +1,子被覆盖为父的值
│
└── childLink({ value: $count }) ← @Link:双向同步
子点 + → 子 +1,父也跟着 +1
父点 + → 父 +1,子也跟着 +1