前置知识: HarmonyOS

状态管理

2 minIntermediate2026/6/14

@State/@Prop/@Link等装饰器

概述

HarmonyOS 的状态管理通过装饰器实现,不同装饰器控制数据的流向和同步范围。@State 管理组件内部状态,@Prop 和 @Link 实现父子组件通信,@Provide 和 @Consume 实现跨层级数据共享。

基础概念

状态装饰器对比

装饰器数据流向同步适用场景
@State组件内部单向组件私有状态
@Prop父 -> 子单向子组件只读展示
@Link父 <-> 子双向子组件需要修改父状态
@Provide祖先 -> 后代单向跨层级共享
@Consume消费祖先数据双向跨层级访问和修改
@Watch监听变化-响应状态变化执行逻辑
@StorageLinkAppStorage双向应用级持久化状态

快速上手

@State 组件内部状态

@Entry
@Component
struct StateDemo {
  @State count: number = 0
  @State message: string = '点击按钮计数'

  build() {
    Column() {
      Text(this.message).fontSize(20)
      Text(`当前计数: ${this.count}`).fontSize(30).margin({ top: 20 })

      Row() {
        Button('-').onClick(() => this.count--)
        Button('+').onClick(() => this.count++)
      }.margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
// 子组件:使用 @Link 双向同步
@Component
struct Counter {
  @Link count: number

  build() {
    Row() {
      Button('-').onClick(() => this.count--)
      Text(`${this.count}`).fontSize(24).margin({ left: 10, right: 10 })
      Button('+').onClick(() => this.count++)
    }
  }
}

// 父组件
@Entry
@Component
struct Parent {
  @State score: number = 0

  build() {
    Column() {
      Text(`分数: ${this.score}`).fontSize(30)
      // 使用 $ 语法传递 @Link 引用
      Counter({ count: $score })
    }
  }
}

详细用法

@Provide 和 @Consume 跨层级通信

// 祖先组件提供数据
@Entry
@Component
struct GrandParent {
  @Provide theme: string = 'light'

  build() {
    Column() {
      Text(`当前主题: ${this.theme}`)
      Button('切换主题')
        .onClick(() => this.theme = this.theme === 'light' ? 'dark' : 'light')
      // 中间层不需要传递 theme
      MiddleLayer()
    }
  }
}

@Component
struct MiddleLayer {
  build() {
    Column() {
      Text('中间层')
      DeepChild()
    }
  }
}

// 深层组件消费数据
@Component
struct DeepChild {
  @Consume theme: string

  build() {
    Text(`深层组件使用的主题: ${this.theme}`)
      .fontColor(this.theme === 'dark' ? Color.White : Color.Black)
      .backgroundColor(this.theme === 'dark' ? '#333' : '#FFF')
      .padding(20)
  }
}

@Watch 监听状态变化

@Entry
@Component
struct WatchDemo {
  @State @Watch('onPriceChange') price: number = 100
  @State @Watch('onQuantityChange') quantity: number = 1
  @State total: number = 100

  // 价格变化时重新计算总价
  onPriceChange() {
    this.total = this.price * this.quantity
  }

  // 数量变化时重新计算总价
  onQuantityChange() {
    this.total = this.price * this.quantity
  }

  build() {
    Column() {
      Text(`单价: ${this.price}`)
      Slider({ value: this.price, min: 1, max: 1000 })
        .onChange((value) => this.price = value)

      Text(`数量: ${this.quantity}`)
      Slider({ value: this.quantity, min: 1, max: 100 })
        .onChange((value) => this.quantity = value)

      Text(`总价: ${this.total}`).fontSize(30).fontWeight(FontWeight.Bold)
    }.padding(20)
  }
}

AppStorage 应用级状态

// 在 EntryAbility 中初始化 AppStorage
AppStorage.setOrCreate('token', '')
AppStorage.setOrCreate('userId', '')

// 在任意组件中使用 @StorageLink
@Entry
@Component
struct StorageDemo {
  @StorageLink('token') token: string = ''
  @StorageLink('userId') userId: string = ''

  build() {
    Column() {
      Text(`用户ID: ${this.userId}`)
      Text(`Token: ${this.token}`)

      Button('登录')
        .onClick(() => {
          this.userId = 'user_123'
          this.token = 'abc123xyz'
        })

      Button('退出')
        .onClick(() => {
          this.userId = ''
          this.token = ''
        })
    }
  }
}

常见场景

表单状态管理

@Entry
@Component
struct FormDemo {
  @State username: string = ''
  @State password: string = ''
  @State isLoading: boolean = false
  @State errorMsg: string = ''

  build() {
    Column() {
      TextInput({ placeholder: '用户名' })
        .onChange((value) => {
          this.username = value
          this.errorMsg = ''
        })

      TextInput({ placeholder: '密码' })
        .type(InputType.Password)
        .onChange((value) => {
          this.password = value
          this.errorMsg = ''
        })

      if (this.errorMsg) {
        Text(this.errorMsg).fontColor(Color.Red).fontSize(14)
      }

      Button('登录')
        .enabled(!this.isLoading)
        .onClick(async () => {
          this.isLoading = true
          try {
            await this.login()
          } catch (e) {
            this.errorMsg = '登录失败'
          } finally {
            this.isLoading = false
          }
        })
    }.padding(20)
  }

  async login() {
    // 登录逻辑
  }
}

注意事项

  • @State 修饰的变量型变更会导致整个组件重新渲染,避免频繁变更引用
  • @Prop 是单向的,子组件修改不会影响父组件
  • @Link 使用 $ 语法传递引用,不是值传递
  • @Provide/@Consume 通过变量名匹配,确保名称一致
  • @Watch 回调在状态变更后同步执行,不要在回调中做耗时操作
  • @StorageLink 修改会同步到 AppStorage,所有使用该 key 的组件都会更新

进阶用法

LocalStorage 页面级状态

// LocalStorage 是页面级的状态存储,比 AppStorage 作用范围更小
let storage: LocalStorage = new LocalStorage()

@Entry(storage)
@Component
struct LocalStorageDemo {
  @LocalStorageLink('count') count: number = 0

  build() {
    Column() {
      Text(`计数: ${this.count}`)
      Button('增加').onClick(() => this.count++)
    }
  }
}