鸿蒙 @Once装饰器:初始化同步一次 解析

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、核心概述

@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 })
        }
      })
    }
  }
}

五、总结

核心价值:

  1. 初始化隔离:确保组件使用固定的初始值,不受父组件后续变化影响
  2. 性能优化:避免不必要的数据同步和组件刷新
  3. 意图明确:明确表达"只使用初始值"的设计意图

适用场景:

  • 配置信息:应用主题、语言设置等初始化配置
  • 初始状态:初始参数等不会变化的设置
  • 大型数据:避免大型数据集的不必要同步
  • 引用隔离:需要与父组件数据隔离的场景

使用限制:

  • 必须与@Param装饰器配合使用
  • 只能在@ComponentV2装饰的组件中使用

@Once装饰器通过提供精确的初始化控制,特别适合需要固定初始值且不希望受外部变化影响的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值