一、背景

目前项目基于鸿蒙V2组件开发,而之前项目是以V1组件为主,所以对V2组件状态装饰器的使用限制或与V1的核心差异认知较浅;为快速掌握V2组件状态管理逻辑,本文结合鸿蒙官方文档和实际开发场景,梳理 V2 组件核心状态装饰器的用法、特性,并对比 V1 组件的差异,形成参考

二、状态装饰器对比

装饰器

核心能力

V1 对应装饰器

核心差异(V2 vs V1

@Local

组件内部只读状态(禁止外部初始化)

@State

V1 @State 允许外部初始化,V2 @Local 禁止

@Param

父传子单向只读状态

@Prop

V2 @Param 禁止子组件修改(编译报错),V1 @Prop 允许本地修改

@Once

配合 @Param 解绑父组件绑定

V1无,V2专属,V2 用于实现 @Param 本地可修改

@Event

子传父回调函数

无(需自定义回调)

V1无,V2专属,V2 标准化子传父逻辑

@Provider

跨组件层级提供状态

@Provide

V2 强制别名匹配、禁止外部初始化、支持重载

@Consumer

跨组件层级消费状态

@Consume

V2 必须本地初始化(兜底默认值)、支持函数类型

三、详细解析

3.1、组件内部状态:@Local(V2 专属)

定义:组件内部的私有状态变量,具备 “变化观察能力”,完全禁止外部初始化 / 修改,仅能在组件内部初始化和更新。

与V1组件@State对比:

用法

@State

@Local

参数

无。

无。

从父组件初始化

可选。

不允许外部初始化。

观察能力

能观测变量本身以及一层的成员属性,无法深度观测。

能观测变量本身,深度观测依赖@Trace装饰器。

数据传递

可以作为数据源和子组件中状态变量同步。

可以作为数据源和子组件中状态变量同步。

@Entry
@ComponentV2
struct Index {
  // 仅内部初始化,外部无法修改/传入
  @Local count: number = 0;

  build() {
    Column() {
      Text(`当前计数:${this.count}`)
      // 内部可修改,触发UI刷新
      Button('+1').onClick(() => this.count++)
      // 传递给子组件@Param
      Child({ num: this.count })
    }
  }
}

3.2、父传子单向状态:@Param

定义:父组件向子组件传递的单向只读状态,子组件禁止直接修改,仅能通过 @Event 通知父组件更新,或搭配 @Once 解绑后本地修改。

与V1组件@Prop和@Link对比

维度

V2 @Param

V1 @Prop

V1 @Link

传递方向

单向(父→子)

单向(父→子)

双向(父↔子)

子组件修改权限

禁止(编译报错)

允许修改本地副本(不影响父,不会同步给父)

允许修改(同步父组件)

本地初始化

支持(兜底默认值)

支持

不支持

刷新触发

仅父改触发子刷新

父改触发子刷新 / 子改仅自身

父子互改互相触发刷新

@Param + @Once用法

定义:@Once 让 @Param 仅初始化同步一次父值,之后解绑为子组件本地普通变量,可自由修改(与父组件解耦)。

// 子组件
@ComponentV2
struct Child {
  // 仅初始化同步父值,后续可本地修改
  @Once @Param num: number = 0;

  build() {
    Column() {
      Text(`子组件数值:${this.num}`)
      // 允许本地修改(仅子组件生效)
      Button('子组件修改').onClick(() => this.num++)
    }
  }
}

3.3、子传父回调:@Event(V2 专属)

定义:子组件向父组件传递数据 / 事件的标准化回调函数,配合 @Param 实现 “可控式双向通信”(替代 V1 @Link)

同步机制:子组件调用 @Event 后,父组件值立刻更新,但子组件 @Param 同步为异步(渲染前生效);

与V1对比:V1无此装饰器,需要自定义回调函数

3.4、跨组件状态共享:@Provider + @Consumer

定义:跨多层组件的状态共享方案(替代 V1 同名装饰器),@Provider 提供状态,@Consumer 消费状态,核心通过 “别名(alias)” 匹配。

特性

V2 @Provider/@Consumer

V1 @Provide/@Consume

@Consumer 初始化

必须本地初始化(找不到 @Provider 时用默认值)

API20 前禁止初始化(找不到抛异常),API20 后支持默认值

支持类型

支持 function 类型

不支持 function 类型

观察能力

观测自身赋值变化,深度观测需 @Trace

观测第一层变化,深度观测需 @Observed/@ObjectLink

别名匹配

alias 是唯一匹配 key(默认用变量名)

优先匹配 alias,匹配不到可匹配变量名

@Provider 初始化

禁止外部初始化

允许外部初始化

重载支持

默认开启(就近匹配)

默认关闭(需配置 allowOverride)

// 父组件:提供状态
@Entry
@ComponentV2
struct Index {
  // 未显式指定alias,默认用变量名'shareData'
  @Provider() shareData: string = '全局共享数据';

  build() {
    Column() {
      Child()
    }
  }
}

// 子组件:消费状态
@ComponentV2
struct Child {
  // 指定alias='shareData',匹配父组件@Provider
  @Consumer('shareData') data: string = '兜底默认值';

  build() {
    Text(`共享数据:${this.data}`) // 显示“全局共享数据”
  }
}

备注:如果没有@Provider(),会直接显示@Consumer定义的默认值

四、V1 —> V2 迁移总结

1、内部状态:V1 @State → V2 @Local(禁止外部初始化,只能组件内部初始化)

2、父传子:V1 @Prop → V2 @Param(禁止子组件修改,支持本地初始化)

3、双向通信:V1 @Link → V2 @Param + @Event(显示回调)

4、跨组件共享:V1 @Provide/@Consume → V2 @Provider/@Consumer(强制别名匹配)

5、本地修改父传值:V1@Prop直接修改 → V2需@Param + @Once

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐