鸿蒙开发状态管理 V2 全部装饰器详解速查表

总览表

装饰器 作用 使用位置
@ComponentV2 声明 V2 自定义组件 struct
@ObservedV2 标记类为可深度观察 class
@Trace 标记属性参与精确刷新 @ObservedV2 类的属性 1
@Local 组件内部响应式状态 @ComponentV2 组件内
@Param 父→子单向输入 @ComponentV2 组件内
@Once 仅首次初始化同步 配合 @Param 使用
@Require 强制父组件必传 配合 @Param 使用
@Event 子→父事件输出 @ComponentV2 组件内
@Provider / @Consumer 跨层级状态共享 @ComponentV2 组件内
@Monitor 状态变化监听 组件内 / @ObservedV2 类内 2
@Computed 缓存派生计算属性 组件内 / @ObservedV2 类内 2
@Type 标记类属性的运行时类型 @ObservedV2 类属性 1
@ReusableV2 V2 版本组件复用 @ComponentV2 组件

逐一详解

1. @ComponentV2 ------ V2 组件声明

V1 用 @Component,V2 用 @ComponentV2。两者不能混用@ComponentV2 组件内只能用 V2 装饰器。34

typescript 复制代码
@ComponentV2
struct MyComponent {
  build() {
    Column() {
      Text('这是 V2 组件')
    }
  }
}

2. @ObservedV2 + @Trace ------ 深度可观察数据模型

V1 的 @Observed 只能观察一级属性变化;V2 的 @ObservedV2 配合 @Trace 实现属性级别的深度精确刷新。1

typescript 复制代码
@ObservedV2
class Address {
  @Trace city: string = '北京'
  @Trace zipCode: string = '100000'
}

@ObservedV2
class Person {
  @Trace name: string = '张三'
  @Trace age: number = 25
  @Trace address: Address = new Address()  // 嵌套对象也能被追踪
}

关键规则

  • @ObservedV2 单独使用无效 ,必须搭配 @Trace1
  • @Trace 只能出现在 @ObservedV2 修饰的类中12
  • 修改 @Trace 属性时,只有该属性对应的 UI 被刷新,而非整个组件重绘

3. @Local ------ 组件内部状态(替代 V1 的 @State

typescript 复制代码
@ComponentV2
struct Counter {
  @Local count: number = 0           // 简单类型
  @Local user: Person = new Person() // 引用类型(配合 @ObservedV2)

  build() {
    Column() {
      Text(`计数: ${this.count}`)
      Button('+1').onClick(() => {
        this.count++  // 触发 UI 刷新
      })
    }
  }
}

@State 的区别@Local 只能局部初始化,不能从外部传入,语义更明确。


4. @Param ------ 父→子单向输入(替代 V1 的 @Prop

typescript 复制代码
@ComponentV2
struct ChildView {
  @Param title: string = ''           // 可选,有默认值
  @Require @Param user: Person        // 必传,配合 @Require
  @Param count: number = 0

  build() {
    Column() {
      Text(this.title)
      Text(`${this.user.name}, ${this.user.age}`)
      Text(`count: ${this.count}`)
    }
  }
}

// 父组件使用
@Entry
@ComponentV2
struct ParentView {
  @Local person: Person = new Person()

  build() {
    ChildView({
      title: '用户信息',    // 传入
      user: this.person,    // 必传
      // count 可省略,使用默认值 0
    })
  }
}

注意@Param 在子组件内只读 ,不能直接修改其本身,但可以修改其 @Trace 属性(如 this.user.name)。


5. @Once ------ 仅初始化同步一次

配合 @Param 使用,初始化后父组件变更不再同步到子组件。

typescript 复制代码
@ComponentV2
struct PriorityBadge {
  @Once @Param priority: number = 0   // 创建时确定,后续不再更新

  build() {
    Text(this.getLabel())
      .fontColor(this.getColor())
  }

  getLabel(): string {
    return ['低', '中', '高'][this.priority]
  }
  getColor(): string {
    return ['#27AE60', '#F39C12', '#E74C3C'][this.priority]
  }
}

适用场景:创建后不会改变的"快照"数据,如优先级标签、创建时间等。


6. @Require ------ 强制父组件必传

typescript 复制代码
@ComponentV2
struct UserCard {
  @Require @Param name: string    // 父组件必须传,没有默认值
  @Param age: number = 0          // 可选

  build() {
    Row() {
      Text(this.name)
      Text(`${this.age}岁`)
    }
  }
}

// 使用
UserCard({ name: '李四', age: 30 })  // ✅ 必须传 name
// UserCard({})                        // ❌ 编译报错:name 必须传

7. @Event ------ 子→父事件输出(替代 V1 的 @Link

V2 取消了隐式双向绑定,子→父通信必须通过 @Event 显式回调。

typescript 复制代码
@ComponentV2
struct TaskCard {
  @Require @Param task: TaskItem
  @Event onToggleComplete: (id: string) => void   // 事件回调
  @Event onDelete: (id: string) => void

  build() {
    Row() {
      Checkbox()
        .select(this.task.completed)
        .onChange(() => {
          this.onToggleComplete(this.task.id)    // 通知父组件
        })
      Text(this.task.title).layoutWeight(1)
      Button('删除').onClick(() => {
        this.onDelete(this.task.id)
      })
    }
  }
}

// 父组件
@Entry
@ComponentV2
struct TaskList {
  @Local tasks: TaskItem[] = []

  build() {
    ForEach(this.tasks, (task: TaskItem) => {
      TaskCard({
        task: task,
        onToggleComplete: (id: string) => {
          // 父组件负责修改数据,然后通过 @Param 同步回子组件
          const t = this.tasks.find(t => t.id === id)
          if (t) t.completed = !t.completed
        },
        onDelete: (id: string) => {
          this.tasks = this.tasks.filter(t => t.id !== id)
        }
      })
    })
  }
}

数据流向父→子(@Param) + 子→父(@Event) = 显式单向数据流。


8. @Provider / @Consumer ------ 跨层级共享(替代 V1 的 @Provide / @Consume

无需逐层 @Param 传递,祖先发布、后代自动订阅。

typescript 复制代码
@ObservedV2
class AppConfig {
  @Trace theme: string = 'light'
  @Trace fontSize: number = 14
}

@Entry
@ComponentV2
struct MainPage {
  @Provider() config: AppConfig = new AppConfig()   // 发布

  build() {
    Column() {
      Text('主页')
      MiddleComponent()   // ← 中间组件无需显式传参
    }
  }
}

@ComponentV2
struct MiddleComponent {
  build() {
    Column() {
      Text('中间组件')
      DeepChild()        // ← 也没有显式传参
    }
  }
}

@ComponentV2
struct DeepChild {
  @Consumer() config: AppConfig = new AppConfig()    // 自动订阅

  build() {
    Column() {
      Text(`当前主题: ${this.config.theme}`)
      Text(`字体大小: ${this.config.fontSize}`)
    }
  }
}

关键规则 :默认按变量名(config)匹配 @Provider@Consumer,双向同步。


9. @Monitor ------ 状态变化监听(替代 V1 的 @Watch

支持深层路径监听 ,这是 V1 的 @Watch 做不到的。

typescript 复制代码
@ObservedV2
class TaskItem {
  @Trace id: string = ''
  @Trace title: string = ''
  @Trace completed: boolean = false
}

@ComponentV2
struct TaskCard {
  @Require @Param task: TaskItem

  // 监听深层属性变化,可获取 before / now
  @Monitor('task.completed')
  onCompletedChange(monitor: IMonitor) {
    const before = monitor.value()?.before
    const now = monitor.value()?.now
    console.info(`任务状态变更: ${before} → ${now}`)
  }

  // 同时监听多个属性
  @Monitor('task.title', 'task.completed')
  onAnyChange(monitor: IMonitor) {
    monitor.dirty.forEach((path: string) => {
      console.info(`${path} 发生了变化`)
    })
  }

  build() {
    Row() {
      Checkbox().select(this.task.completed)
      Text(this.task.title)
    }
  }
}

也可以写在数据类内部

typescript 复制代码
@ObservedV2
class Player {
  @Trace hp: number = 100
  @Trace mp: number = 50

  @Monitor('hp')
  onHpChange(monitor: IMonitor) {
    const before = monitor.value()?.before as number
    const now = monitor.value()?.now as number
    if (now <= 0) {
      console.info('玩家死亡')
    }
  }
}

10. @Computed ------ 缓存派生计算属性

仅在依赖的 @Trace 属性变化时重新计算,避免 build() 中重复运算。

typescript 复制代码
@ObservedV2
class TaskStats {
  @Trace total: number = 0
  @Trace completedCount: number = 0

  @Computed
  get pendingCount(): number {
    return this.total - this.completedCount   // 仅在 total 或 completedCount 变化时重新计算
  }

  @Computed
  get completionRate(): string {
    if (this.total === 0) return '0%'
    return `${Math.round((this.completedCount / this.total) * 100)}%`
  }
}

组件内也可以使用:

typescript 复制代码
@ComponentV2
struct UserInfo {
  @Local firstName: string = ''
  @Local lastName: string = ''

  @Computed
  get fullName(): string {
    return `${this.lastName} ${this.firstName}`   // 缓存,不重复计算
  }

  build() {
    Column() {
      Text(this.fullName)   // 多次引用也只算一次
      Text(this.fullName)
    }
  }
}

11. @Type ------ 标记类属性的运行时类型

用于声明 @Trace 属性的具体类型,辅助运行时类型推断(适用于集合类型等场景)。

typescript 复制代码
@ObservedV2
class DataModel {
  @Trace items: Array<string> = []
  // 标记类型
  @Type(Array<string>)
  @Trace tags: string[] = []

  @Type(Map<string, number>)
  @Trace scoreMap: Map<string, number> = new Map()
}

12. @ReusableV2 ------ V2 版本组件复用

V1 的 @Reusable 对应 V2 的 @ReusableV2,用于长列表中的组件复用优化。

typescript 复制代码
@ReusableV2
@ComponentV2
struct ReusableListItem {
  @Param item: string = ''
  @Param index: number = 0

  aboutToReuse(params: Record<string, Object>): void {
    // 复用前更新数据
    this.item = params.item as string
    this.index = params.index as number
  }

  build() {
    Row() {
      Text(`${this.index}: ${this.item}`)
    }
  }
}

V1 → V2 对照速查

V1 装饰器 25 V2 装饰器 2 核心变化
@Component @ComponentV2 组件声明
@State @Local 不能外部传入,语义更纯
@Prop @Param 单向输入
@Link @Param + @Event 双向绑定拆为显式单向+事件
@Watch @Monitor 支持深层路径监听、获取 before/now
@Provide / @Consume @Provider / @Consumer 按变量名自动匹配
@Observed + @ObjectLink @ObservedV2 + @Trace 属性级精确刷新,支持深层嵌套
@Computed V2 新增:缓存派生值
@Once V2 新增:一次性初始化
@Require V2 新增:强制必传参数
@Reusable @ReusableV2 V2 版本复用

核心设计理念

less 复制代码
                    ┌──────────────────────────┐
                    │      @Provider / @Consumer │  ← 跨层级共享
                    │      (跨组件全局状态)       │
                    └──────────┬───────────────┘
                               │
        ┌──────────────────────┼──────────────────────┐
        ▼                      ▼                      ▼
   @Local                @Param ←──→ @Event       @Computed
  (组件内部状态)         (父→子输入) (子→父输出)   (派生计算)
        │                      │
        └──────────┬───────────┘
                   ▼
           @ObservedV2 + @Trace
           (数据模型层,属性级精确刷新)
                   │
                   ▼
              @Monitor
           (变化监听 + 副作用)

V2 的核心理念:单向数据流 + 显式事件回调,取消隐式双向绑定,数据流向清晰可追踪,状态变化可精确到单个属性级别进行刷新。

相关推荐
爱吃大芒果2 小时前
鸿蒙 ArkTS 网络工程进阶:@ohos.net.http 模块下的长连接、超时与防内存泄漏实战
华为·harmonyos
FrameNotWork2 小时前
HarmonyOS 6.0 沉浸式状态栏与安全区域适配实战
华为·harmonyos
绝世番茄2 小时前
鸿蒙原生ArkTS布局方式之Stack+Opacity叠加淡入淡出深度解析
华为·harmonyos·鸿蒙
心中有国也有家3 小时前
鸿蒙Flutter开发环境从零搭建教程(Windows/macOS双平台·避坑版)
学习·flutter·华为·harmonyos
国服第二切图仔3 小时前
HarmonyOS APP《画伴梦工厂》开发第43篇-多模块架构设计——模块拆分与依赖管理
华为·harmonyos
HarmonyOS_SDK4 小时前
一次开发,多端高效协同:解码HarmonyOS SDK窗口的响应式设计哲学
harmonyos
心中有国也有家5 小时前
Flutter 鸿蒙适配第一步:从 hive 迁移到 hive\_ce
hive·学习·flutter·华为·harmonyos
心中有国也有家6 小时前
AtomGit Flutter 鸿蒙客户端:E-Brufen 架构设计
学习·flutter·华为·harmonyos
hqzing6 小时前
鸿蒙 PC 底层开发技术详解(七):二进制自签名算法的实现
算法·华为·harmonyos