ArkTS 状态管理深度解析
ArkTS 状态管理:@State、@Prop、@Link、@Provide/@Consume 等装饰器的数据流。 讲清单向数据流与组件联动,掌握后能答出「ArkTS 状态怎么从父传到子再回传」。
ArkTS 状态管理深度解析
一句话概括
ArkTS 用 5 个装饰器覆盖所有状态流转场景:@State(组件私有)→ @Prop(父传子单向)→ @Link(父子双向)→ @Provide/@Consume(跨层级广播),核心思想是通过装饰器声明数据流向,框架自动追踪变更并更新 UI。
核心知识点
1. @State——组件私有状态的基石
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
struct Counter {
@State count: number = 0; // 组件内部状态,变更自动刷新 UI
build() {
Column() {
Text(`计数: ${this.count}`).fontSize(24)
Button('+1').onClick(() => this.count++) // 直接改,UI 自动更新
}
}
}
// @State 能观测到第一层属性变化(基础类型赋值、对象属性修改)
// 深层嵌套对象需搭配 @Observed 装饰器类
2. @Prop——父传子单向数据流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
struct ChildLabel {
@Prop label: string; // 父组件传入,子组件不能改原值
@Prop active: boolean = false;
build() {
Text(this.label)
.fontColor(this.active ? '#007AFF' : '#999')
}
}
// 父组件:ChildLabel({ label: this.title, active: this.isSelected })
// 子组件内修改 this.label 不会影响父组件
// 要回传数据?通过回调函数 onXXX
3. @Link——父子双向同步
1
2
3
4
5
6
7
8
9
10
11
12
@Component
struct ChildToggle {
@Link checked: boolean; // 双向绑定,子和父共享同一份数据
build() {
Toggle({ type: ToggleType.Switch, isOn: this.checked })
.onChange((isOn: boolean) => this.checked = isOn)
}
}
// 父组件:ChildToggle({ checked: $isDarkMode })
// ↑ 注意 $ 符号,表示"传引用绑定"而非传值
4. @Provide/@Consume——跨层级免传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 顶层组件
@Component
struct AppRoot {
@Provide('theme') theme: string = 'dark'; // 向下广播
build() { Column() { MainPage() } }
}
// 任意深层子组件(无需通过中间层逐级传递)
@Component
struct DeepChild {
@Consume('theme') theme: string; // 无论多深,直接拿到
build() {
Text(`当前主题: ${this.theme}`)
}
}
// 类比 React Context / Vue provide-inject,解决 props 逐层透传的痛点
5. 五个装饰器的选择决策树
1
2
3
4
5
数据只在当前组件用? → @State
父传子、子只读不写? → @Prop
父传子、子需要修改且同步回父? → @Link(调用时加 $)
祖先后代跨多层,中间组件不需要知道? → @Provide/@Consume
复杂对象且需要深层属性变更触发更新? → @Observed + @ObjectLink
其实你每天都在用
- 开关/复选框:
@State isOn: boolean→ 点击切换后 UI 自动刷新 - 表单输入:
@State username: string→ TextInput 双向绑定,输入即更新 - 主题切换:
@Provide theme在根组件 →@Consume theme在任意深层组件 → 改一处全页面变色 - 列表项状态:
@Link selectedId→ 点击某行高亮,父子组件数据实时同步 - Tab 切换:
@State currentTab: number→ 切 Tab 时所有依赖该状态的组件自动刷新
常见误解(FAQ)
❌ 误区:「@Prop 修改后父组件也能感知」 @Prop 是单向快照,子改了自己的副本不等于父变了。需要回写用 @Link(双向)或者回调函数通知父。
❌ 误区:「@State 能自动观测对象深层嵌套属性」 不能。
@State user: User→ 只监听this.user = newUser这种整体替换,this.user.name = 'new'不会触发更新。需要把 User 类标记为@Observed,属性用@ObjectLink接收。❌ 误区:「@Link 绑定时忘加 $ 也能用」 不加
$传的是值拷贝,子改了自己那份但父不知道——编译器不会报错但你 debug 到怀疑人生。记住口诀:见 @Link 必有$。❌ 误区:「@Provide/@Consume 是全局的,任何组件都能访问」 作用域限制在组件树内,不是应用全局。祖先 provide 后只有它的子孙组件能 consume,兄弟组件或无关组件拿不到。全局共享建议用 AppStorage。
一句话总结
ArkTS 状态管理的精髓就一句话:装饰器声明数据流向,框架追踪变更刷新 UI——你只管声明”这个数据属于谁、往哪流”,剩下的框架来做。
本文由作者按照 CC BY 4.0 进行授权