本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、核心概述
@Once装饰器是ArkUI状态管理V2中用于处理一次性初始化场景的特殊装饰器,专为@ComponentV2装饰的自定义组件设计。它允许子组件在创建时从父组件接收初始值,但后续父组件数据的变化不会同步到子组件。
核心特性:
- 一次性初始化:只在组件创建时接受外部传入值进行初始化
- 阻断同步:后续数据源更改不会同步给子组件
- 必须搭配使用:必须与@Param装饰器配合使用,不能单独使用
- 本地修改支持:初始化后可以在组件内部修改@Param变量的值
- API version 12+支持:从API version 12开始支持在元服务中使用
二、@Once基础使用
@Once装饰器作为@Param的辅助装饰器,主要作用是拦截数据源的变化同步:
@ComponentV2
struct UserProfileCard {
// 正确用法:@Once与@Param搭配使用
@Param @Once userRole: string = "普通用户";
@Param @Once initialScore: number = 100;
// 错误用法:@Once不能单独使用
// @Once standaloneValue: string = "错误"; // 编译错误
build() {
Column() {
Text(`用户角色: ${this.userRole}`)
Text(`初始积分: ${this.initialScore}`)
Button("本地修改积分")
.onClick(() => {
// 允许在组件内部修改值
this.initialScore += 10;
})
}
}
}
@Entry
@Component
struct ParentComponent {
@State currentRole: string = "管理员";
@State dynamicScore: number = 200;
build() {
Column() {
// 传入初始值
UserProfileCard({
userRole: this.currentRole,
initialScore: this.dynamicScore
})
Button("变更父组件数据")
.onClick(() => {
// 父组件数据变化不会同步到子组件
this.currentRole = "超级管理员";
this.dynamicScore = 300;
})
}
}
}
三、装饰器说明
3.1 @Once装饰器规范
| 属性 | 说明 |
|---|---|
| 装饰器参数 | 无 |
| 使用条件 | 必须与@Param装饰器配合使用 |
| 可装饰变量类型 | 与@Param支持的变量类型一致 |
| 装饰顺序 | @Once与@Param的先后顺序不影响功能 |
3.2 使用限制
// 正确用法示例
@ComponentV2
struct CorrectUsage {
@Param @Once configData: AppConfig = new AppConfig(); // 正确
@Once @Param themeSetting: string = "light"; // 正确,顺序不影响
}
// 错误用法示例
@ComponentV2
struct IncorrectUsage {
@Once aloneValue: string = "错误"; // 编译错误:@Once不能单独使用
@Local @Once mixedDecorator: number = 0; // 编译错误:不能与其他装饰器混用(除@Param外)
}
四、与@Param的对比
5.1 行为差异对比
@ComponentV2
struct ComparisonDemo {
@Param normalParam: string = "默认"; // 普通@Param,会同步更新
@Param @Once onceParam: string = "初始"; // @Once @Param,只初始化一次
build() {
Column() {
Text(`普通参数: ${this.normalParam}`) // 会随父组件更新
Text(`一次性参数: ${this.onceParam}`) // 只保持初始值
Button("本地修改测试")
.onClick(() => {
// 两者都允许本地修改
this.normalParam = "本地修改";
this.onceParam = "本地修改";
})
}
}
}
@Entry
@Component
struct ParentDemo {
@State dynamicValue: string = "父组件值";
build() {
Column() {
ComparisonDemo({
normalParam: this.dynamicValue,
onceParam: this.dynamicValue
})
Button("更新父组件值")
.onClick(() => {
this.dynamicValue = "更新后的值";
// normalParam会更新,onceParam保持不变
})
}
}
}
5.2 性能优化场景
// 使用@Once避免不必要的同步开销
@ComponentV2
struct HeavyComponent {
@Param @Once heavyData: LargeDataset; // 大型数据集只初始化一次
build() {
List() {
ForEach(this.heavyData.items, (item) => {
ListItem() {
ComplexItemRenderer({ data: item })
}
})
}
}
}
五、总结
核心价值:
- 初始化隔离:确保组件使用固定的初始值,不受父组件后续变化影响
- 性能优化:避免不必要的数据同步和组件刷新
- 意图明确:明确表达"只使用初始值"的设计意图
适用场景:
- 配置信息:应用主题、语言设置等初始化配置
- 初始状态:初始参数等不会变化的设置
- 大型数据:避免大型数据集的不必要同步
- 引用隔离:需要与父组件数据隔离的场景
使用限制:
- 必须与@Param装饰器配合使用
- 只能在
@ComponentV2装饰的组件中使用
@Once装饰器通过提供精确的初始化控制,特别适合需要固定初始值且不希望受外部变化影响的场景。

被折叠的 条评论
为什么被折叠?



