HarmonyOS状态管理入门:@State与@Link装饰器的原理与实践
状态管理是声明式UI开发的核心概念。本文将深入讲解HarmonyOS中最基础且最重要的两个状态装饰器:@State和@Link,帮助你掌握组件内状态管理和父子组件状态同步的核心技能。
一、状态管理基础概念
1.1 什么是状态管理
@Component
struct StateBasicConcept {
// 普通变量 - 不会触发UI更新
normalCount: number = 0
// @State装饰的变量 - 变化时自动更新UI
@State stateCount: number = 0
build() {
Column({ space: 20 }) {
Text('状态管理基础概念')
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 普通变量演示
Text(`普通变量: ${this.normalCount}`)
.fontSize(16)
.fontColor('#666')
// @State变量演示
Text(`@State变量: ${this.stateCount}`)
.fontSize(16)
.fontColor('#007DFF')
.fontWeight(FontWeight.Bold)
Row({ space: 15 }) {
Button('普通变量+1')
.onClick(() => {
this.normalCount++
console.log('普通变量值:', this.normalCount) // 值会变化,但UI不会更新
})
Button('@State变量+1')
.onClick(() => {
this.stateCount++ // 值变化,UI自动更新
})
}
// 状态变化监听
Text('状态变化日志:')
.fontSize(14)
.fontColor('#333')
.margin({ top: 20 })
}
.width('100%')
.padding(20)
}
}
1.2 状态管理的核心原理
@Component
struct StatePrincipleDemo {
@State private userInfo: User = {
name: '张三',
age: 25,
isVIP: false
}
build() {
Column({ space: 15 }) {
Text('状态管理原理演示')
.fontSize(18)
.fontWeight(FontWeight.Bold)
// 对象状态演示
Text(`用户名: ${this.userInfo.name}`)
.fontSize(16)
Text(`年龄: ${this.userInfo.age}`)
.fontSize(16)
Text(`VIP状态: ${this.userInfo.isVIP ? '是' : '否'}`)
.fontSize(16)
.fontColor(this.userInfo.isVIP ? '#FF9500' : '#666')
Divider()
Text('状态更新操作:').fontSize(14).fontColor('#333')
Row({ space: 10 }) {
Button('修改名字')
.onClick(() => {
// 错误方式:直接修改属性不会触发更新
// this.userInfo.name = '李四'
// 正确方式:创建新对象
this.userInfo = {
...this.userInfo,
name: '李四'
}
})
Button('增加年龄')
.onClick(() => {
this.userInfo = {
...this.userInfo,
age: this.userInfo.age + 1
}
})
Button('切换VIP')
.onClick(() => {
this.userInfo = {
...this.userInfo,
isVIP: !this.userInfo.isVIP
}
})
}
}
.width('100%')
.padding(20)
}
}
class User {
name: string = ''
age: number = 0
isVIP: boolean = false
}
二、@State装饰器深度解析
2.1 @State基础用法
@Component
struct StateBasicUsage {
// 基本类型状态
@State count: number = 0
@State message: string = 'Hello'
@State isActive: boolean = false
// 数组类型状态
@State numberList: number[] = [1, 2, 3]
@State stringList: string[] = ['A', 'B', 'C']
// 对象类型状态
@State config: Config = {
theme: 'light',
fontSize: 16,
language: 'zh-CN'
}
build() {
Column({ space: 20 }) {
Text('@State基础用法')
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 基本类型状态展示
this.buildBasicStateDemo()
// 数组类型状态展示
this.buildArrayStateDemo()
// 对象类型状态展示
this.buildObjectStateDemo()
}
.width('100%')
.padding(20)
}
@Builder
buildBasicStateDemo() {
Column({ space: 10 }) {
Text('基本类型状态').fontSize(16).fontWeight(FontWeight.Medium)
Row({ space: 15 }) {
Text(`计数: ${this.count}`).fontSize(14)
Text(`消息: ${this.message}`).fontSize(14)
Text(`活跃: ${this.isActive}`).fontSize(14)
}
Row({ space: 10 }) {
Button('计数+')
.onClick(() => this.count++)
Button('改消息')
.onClick(() => this.message = 'Hello HarmonyOS')
Button('切换状态')
.onClick(() => this.isActive = !this.isActive)
}
}
.width('100%')
.padding(15)
.backgroundColor('#F8F9FA')
.borderRadius(8)
}
@Builder
buildArrayStateDemo() {
Column({ space: 10 }) {
Text('数组类型状态').fontSize(16).fontWeight(FontWeight.Medium)
Text(`数组: [${this.numberList.join(', ')}]`).fontSize(14)
Row({ space: 10 }) {
Button('添加元素')
.onClick(() => {
this.numberList = [...this.numberList, this.numberList.length + 1]
})
Button('删除元素')
.onClick(() => {
if (this.numberList.length > 0) {
this.numberList = this.numberList.slice(0, -1)
}
})
Button('清空数组')
.onClick(() => {
this.numberList = []
})
}
}
.width('100%')
.padding(15)
.backgroundColor('#F8F9FA')
.borderRadius(8)
}
@Builder
buildObjectStateDemo() {
Column({ space: 10 }) {
Text('对象类型状态').fontSize(16).fontWeight(FontWeight.Medium)
Text(`主题: ${this.config.theme}`).fontSize(14)
Text(`字体: ${this.config.fontSize}`).fontSize(14)
Text(`语言: ${this.config.language}`).fontSize(14)
Row({ space: 10 }) {
Button('切换主题')
.onClick(() => {
this.config = {
...this.config,
theme: this.config.theme === 'light' ? 'dark' : 'light'
}
})
Button('增大字体')
.onClick(() => {
this.config = {
...this.config,
fontSize: this.config.fontSize + 2
}
})
Button('切换语言')
.onClick(() => {
this.config = {
...this.config,
language: this.config.language === 'zh-CN' ? 'en-US' : 'zh-CN'
}
})
}
}
.width('100%')
.padding(15)
.backgroundColor('#F8F9FA')
.borderRadius(8)
}
}
class Config {
theme: string = 'light'
fontSize: number = 16
language: string = 'zh-CN'
}
2.2 @State高级特性
@Component
struct StateAdvancedFeatures {
@State @Watch('onCountChange') count: number = 0
@State @Watch('onUserChange') user: User = new User()
// 状态变化监听
onCountChange(): void {
console.log('count发生变化:', this.count)
}
onUserChange(): void {
console.log('user发生变化:', JSON.stringify(this.user))
}
build() {
Column({ space: 20 }) {
Text('@State高级特性')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(`计数: ${this.count}`).fontSize(16)
Text(`用户名: ${this.user.name}`).fontSize(16)
Text(`年龄: ${this.user.age}`).fontSize(16)
Row({ space: 10 }) {
Button('计数+')
.onClick(() => this.count++)
Button('修改用户')
.onClick(() => {
this.user = new User()
this.user.name = '李四'
this.user.age = 30
})
}
// 状态依赖演示
this.buildComputedState()
}
.width('100%')
.padding(20)
}
@Builder
buildComputedState() {
// 计算属性(基于其他状态)
const doubleCount: number = this.count * 2
const isAdult: boolean = this.user.age >= 18
const userStatus: string = `${this.user.name} (${isAdult ? '成年' : '未成年'})`
Column({ space: 10 }) {
Text('计算属性演示').fontSize(16).fontWeight(FontWeight.Medium)
Text(`双倍计数: ${doubleCount}`).fontSize(14)
Text(`用户状态: ${userStatus}`).fontSize(14)
Text(`是否成年: ${isAdult ? '是' : '否'}`)
.fontSize(14)
.fontColor(isAdult ? '#34C759' : '#FF9500')
}
.width('100%')
.padding(15)
.backgroundColor('#F0F8FF')
.borderRadius(8)
}
}
三、@Link装饰器深度解析
3.1 @Link基础用法
@Component
struct ParentComponent {
@State parentCount: number = 0
@State parentMessage: string = '父组件消息'
build() {
Column({ space: 20 }) {
Text('父组件')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text(`父组件计数: ${this.parentCount}`).fontSize(16)
Text(`父组件消息: ${this.parentMessage}`).fontSize(16)
Row({ space: 10 }) {
Button('父组件+1')
.onClick(() => this.parentCount++)
Button('修改消息')
.onClick(() => this.parentMessage = '消息已修改')
}
Divider().margin({ top: 10, bottom: 10 })
// 子组件 - 使用@Link建立双向绑定
ChildComponent({
childCount: $parentCount, // 双向绑定
childMessage: this.parentMessage // 单向传递
})
}
.width('100%')
.padding(20)
.backgroundColor('#E3F2FD')
.borderRadius(12)
}
}
@Component
struct ChildComponent {
@Link childCount: number // 与父组件双向绑定
@Prop childMessage: string // 从父组件单向接收
@State localCount: number = 0 // 子组件本地状态
build() {
Column({ space: 15 }) {
Text('子组件')
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(`@Link计数: ${this.childCount}`)
.fontSize(14)
.fontColor('#007DFF')
Text(`@Prop消息: ${this.childMessage}`)
.fontSize(14)
.fontColor('#666')
Text(`本地计数: ${this.localCount}`)
.fontSize(14)
.fontColor('#999')
Row({ space: 10 }) {
Button('@Link+1')
.onClick(() => {
this.childCount++ // 会同步到父组件
})
Button('本地+1')
.onClick(() => {
this.localCount++ // 只影响子组件
})
}
Text('说明: @Link修改会影响父组件,@Prop只能读取')
.fontSize(12)
.fontColor('#FF6B6B')
}
.width('90%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.border({ width: 2, color: '#007DFF' })
}
}
3.2 @Link高级应用
@Component
struct ComplexParentComponent {
@State userList: User[] = [
new User('张三', 25),
new User('李四', 30),
new User('王五', 28)
]
@State selectedUserIndex: number = 0
build() {
Column({ space: 20 }) {
Text('复杂数据@Link演示')
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('用户列表:').fontSize(16).fontWeight(FontWeight.Medium)
// 用户列表展示
ForEach(this.userList, (user: User, index: number) => {
Row({ space: 10 }) {
Text(`${index + 1}. ${user.name} - ${user.age}岁`)
.fontSize(14)
.layoutWeight(1)
Button('选择')
.onClick(() => this.selectedUserIndex = index)
.stateEffect(this.selectedUserIndex === index)
}
.width('100%')
.padding(10)
.backgroundColor(this.selectedUserIndex === index ? '#E3F2FD' : '#F5F5F5')
.borderRadius(6)
})
Divider()
// 用户编辑组件
if (this.selectedUserIndex >= 0) {
UserEditorComponent({
user: $userList[this.selectedUserIndex] // 双向绑定数组中的对象
})
}
}
.width('100%')
.padding(20)
}
}
@Component
struct UserEditorComponent {
@Link user: User
@State localEdit: boolean = false
@State tempName: string = ''
@State tempAge: number = 0
build() {
Column({ space: 15 }) {
Text('用户编辑器')
.fontSize(16)
.fontWeight(FontWeight.Bold)
if (!this.localEdit) {
// 显示模式
Text(`当前用户: ${this.user.name}`).fontSize(14)
Text(`年龄: ${this.user.age}`).fontSize(14)
Button('编辑模式')
.onClick(() => {
this.tempName = this.user.name
this.tempAge = this.user.age
this.localEdit = true
})
} else {
// 编辑模式
TextInput({ placeholder: '输入姓名', text: this.tempName })
.onChange((value: string) => {
this.tempName = value
})
TextInput({ placeholder: '输入年龄', text: this.tempAge.toString() })
.onChange((value: string) => {
this.tempAge = parseInt(value) || 0
})
Row({ space: 10 }) {
Button('保存')
.onClick(() => {
this.user.name = this.tempName
this.user.age = this.tempAge
this.localEdit = false
})
Button('取消')
.onClick(() => {
this.localEdit = false
})
}
}
}
.width('100%')
.padding(15)
.backgroundColor('#F8F9FA')
.borderRadius(8)
}
}
四、@State与@Link对比实践
4.1 综合对比演示
@Component
struct StateVsLinkDemo {
@State globalCount: number = 0
@State userData: UserData = new UserData()
build() {
Column({ space: 25 }) {
Text('@State vs @Link 综合对比')
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor('#007DFF')
// 全局状态展示
this.buildGlobalState()
// 组件对比演示
Row({ space: 20 }) {
// @State管理的子组件
StateManagedComponent({
localCount: this.globalCount
})
// @Link管理的子组件
LinkManagedComponent({
linkedCount: $globalCount
})
}
.width('100%')
.height(400)
// 复杂对象状态演示
this.buildObjectStateDemo()
}
.width('100%')
.padding(20)
.backgroundColor('#FFFFFF')
}
@Builder
buildGlobalState() {
Column({ space: 10 }) {
Text('全局状态监控').fontSize(16).fontWeight(FontWeight.Medium)
Row({ space: 20 }) {
Column({ space: 5 }) {
Text(`计数: ${this.globalCount}`).fontSize(14)
Progress({ value: this.globalCount, total: 100 })
.width(100)
.color('#007DFF')
}
Button('重置计数')
.onClick(() => this.globalCount = 0)
}
}
.width('100%')
.padding(15)
.backgroundColor('#F0F8FF')
.borderRadius(8)
}
@Builder
buildObjectStateDemo() {
Column({ space: 15 }) {
Text('对象状态管理').fontSize(16).fontWeight(FontWeight.Medium)
ObjectStateManager({
userData: $userData
})
}
.width('100%')
.padding(15)
.backgroundColor('#FFF8E1')
.borderRadius(8)
}
}
@Component
struct StateManagedComponent {
@Prop localCount: number
@State internalCount: number = 0
build() {
Column({ space: 15 }) {
Text('@State管理组件')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#FF6B6B')
Text('特性:')
.fontSize(14)
.fontWeight(FontWeight.Medium)
Text('• 组件内部状态管理')
.fontSize(12)
Text('• 状态变化触发UI更新')
.fontSize(12)
Text('• 不直接影响父组件')
.fontSize(12)
Divider().margin({ top: 10, bottom: 10 })
Text(`接收的Prop: ${this.localCount}`)
.fontSize(14)
.fontColor('#666')
Text(`内部状态: ${this.internalCount}`)
.fontSize(14)
.fontColor('#007DFF')
Row({ space: 10 }) {
Button('内部+1')
.onClick(() => this.internalCount++)
Button('内部×2')
.onClick(() => this.internalCount *= 2)
}
}
.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#FFEBEE')
.borderRadius(8)
.border({ width: 2, color: '#FF6B6B' })
}
}
@Component
struct LinkManagedComponent {
@Link linkedCount: number
@State operationHistory: string[] = []
build() {
Column({ space: 15 }) {
Text('@Link管理组件')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#4ECDC4')
Text('特性:')
.fontSize(14)
.fontWeight(FontWeight.Medium)
Text('• 与父组件双向绑定')
.fontSize(12)
Text('• 修改会影响父组件')
.fontSize(12)
Text('• 适合状态共享场景')
.fontSize(12)
Divider().margin({ top: 10, bottom: 10 })
Text(`链接的计数: ${this.linkedCount}`)
.fontSize(14)
.fontColor('#007DFF')
Row({ space: 10 }) {
Button('链接+1')
.onClick(() => {
this.linkedCount++
this.addHistory('链接计数+1')
})
Button('链接×2')
.onClick(() => {
this.linkedCount *= 2
this.addHistory('链接计数×2')
})
Button('链接重置')
.onClick(() => {
this.linkedCount = 0
this.addHistory('链接计数重置')
})
}
// 操作历史
if (this.operationHistory.length > 0) {
Column({ space: 5 }) {
Text('操作历史:').fontSize(12).fontColor('#666')
ForEach(this.operationHistory, (history: string) => {
Text(history).fontSize(10).fontColor('#999')
})
}
.margin({ top: 10 })
}
}
.width('100%')
.height('100%')
.padding(15)
.backgroundColor('#E0F7FA')
.borderRadius(8)
.border({ width: 2, color: '#4ECDC4' })
}
private addHistory(operation: string): void {
this.operationHistory = [
`${new Date().toLocaleTimeString()}: ${operation}`,
...this.operationHistory.slice(0, 4) // 只保留最近5条
]
}
}
@Component
struct ObjectStateManager {
@Link userData: UserData
build() {
Column({ space: 10 }) {
Text('用户数据管理器').fontSize(14).fontWeight(FontWeight.Medium)
Text(`姓名: ${this.userData.name}`).fontSize(12)
Text(`年龄: ${this.userData.age}`).fontSize(12)
Text(`积分: ${this.userData.points}`).fontSize(12)
Row({ space: 5 }) {
Button('改名字')
.onClick(() => {
this.userData.name = this.userData.name === '张三' ? '李四' : '张三'
})
Button('加年龄')
.onClick(() => this.userData.age++)
Button('加积分')
.onClick(() => this.userData.points += 10)
}
}
.width('100%')
}
}
class UserData {
name: string = '张三'
age: number = 25
points: number = 100
}
五、最佳实践与常见问题
5.1 状态管理最佳实践
@Component
struct StateBestPractices {
@State private user: User = new User()
@State private loading: boolean = false
@State private error: string = ''
build() {
Column({ space: 20 }) {
Text('状态管理最佳实践')
.fontSize(20)
.fontWeight(FontWeight.Bold)
// 错误处理状态
if (this.error) {
this.buildErrorState()
}
// 加载状态
if (this.loading) {
this.buildLoadingState()
} else {
this.buildContent()
}
// 操作按钮
this.buildActionButtons()
}
.width('100%')
.padding(20)
}
@Builder
buildErrorState() {
Row({ space: 10 }) {
Image($r('app.media.error_icon'))
.width(20)
.height(20)
Text(this.error)
.fontSize(14)
.fontColor('#FF3B30')
}
.width('100%')
.padding(10)
.backgroundColor('#FFEBEE')
.borderRadius(6)
}
@Builder
buildLoadingState() {
Column({ space: 10 }) {
Progress({ value: 50, total: 100 })
.width(200)
Text('加载中...')
.fontSize(14)
.fontColor('#666')
}
.width('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
@Builder
buildContent() {
Column({ space: 15 }) {
Text(`用户: ${this.user.name}`).fontSize(16)
Text(`年龄: ${this.user.age}`).fontSize(16)
Text(`VIP: ${this.user.isVIP ? '是' : '否'}`).fontSize(16)
}
}
@Builder
buildActionButtons() {
Column({ space: 10 }) {
Row({ space: 10 }) {
Button('模拟加载')
.onClick(() => this.simulateLoad())
Button('模拟错误')
.onClick(() => this.simulateError())
Button('重置状态')
.onClick(() => this.resetState())
}
Text('最佳实践提示:')
.fontSize(12)
.fontColor('#666')
.margin({ top: 10 })
Text('1. 使用不可变数据更新状态')
.fontSize(10)
Text('2. 合理使用@Watch监听状态变化')
.fontSize(10)
Text('3. 避免在build()中修改状态')
.fontSize(10)
Text('4. 使用条件渲染处理不同状态')
.fontSize(10)
}
}
private simulateLoad(): void {
this.loading = true
this.error = ''
// 模拟异步加载
setTimeout(() => {
this.loading = false
this.user = {
name: '加载的用户',
age: 30,
isVIP: true
}
}, 2000)
}
private simulateError(): void {
this.loading = true
setTimeout(() => {
this.loading = false
this.error = '模拟错误:数据加载失败'
}, 1000)
}
private resetState(): void {
this.user = new User()
this.loading = false
this.error = ''
}
}
总结
通过本文的深入学习,你应该已经掌握了:
- @State装饰器:组件内部状态管理,状态变化自动更新UI
- @Link装饰器:父子组件双向状态绑定,实现状态共享
- 状态管理原则:不可变数据、合理监听、条件渲染等最佳实践
- 实战应用:各种数据类型的状态管理和组件通信
@State和@Link是HarmonyOS状态管理的基础,熟练掌握它们将为后续学习更复杂的状态管理
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号