当前位置: 首页 > news >正文

鸿蒙中级课程笔记2—状态管理V2—@Local

@Local装饰器:组件内部状态

为了实现对@ComponentV2装饰的自定义组件中变量变化的观测,开发者可以使用@Local装饰器装饰变量。

在阅读本文档前,建议提前阅读:@ComponentV2。常见问题请参考组件内状态变量常见问题。

说明

从API version 12开始,在@ComponentV2装饰的自定义组件中支持使用@Local装饰器。

从API version 12开始,该装饰器支持在元服务中使用。

概述

@Local表示组件内部的状态,使得自定义组件内部的变量具有观察变化的能力:

  • 被@Local装饰的变量无法从外部初始化,因此必须在组件内部进行初始化。

  • 当被@Local装饰的变量变化时,会刷新使用该变量的组件。

  • @Local支持观测number、boolean、string、Object、class等基本类型以及Array、Set、Map、Date等内嵌类型。

  • @Local的观测能力仅限于被装饰的变量本身。当装饰简单类型时,能够观测到对变量的赋值;当装饰对象类型时,仅能观测到对对象整体的赋值;当装饰数组类型时,能观测到数组整体以及数组元素项的变化;当装饰Array、Set、Map、Date等内嵌类型时,可以观测到通过API调用带来的变化。详见观察变化。

  • @Local支持null、undefined以及联合类型。

状态管理V1版本@State装饰器的局限性

状态管理V1使用@State装饰器定义组件中的基础状态变量,该状态变量常用来作为组件内部状态,在组件内使用。但由于@State装饰器又能够从外部初始化,因此无法确保@State装饰变量的初始值一定为组件内部定义的值。

class ComponentInfo { public name: string; public count: number; public message: string; constructor(name: string, count: number, message: string) { this.name = name; this.count = count; this.message = message; } } @Component struct Child { @State componentInfo: ComponentInfo = new ComponentInfo('Child', 1, 'Hello World'); // 父组件传递的componentInfo会覆盖初始值 build() { Column() { Text(`componentInfo.message is ${this.componentInfo.message}`) } } } @Entry @Component struct Index { build() { Column() { Child({ componentInfo: new ComponentInfo('Unknown', 0, 'Error') }) } } }

上述代码中,可以通过在初始化Child自定义组件时传入新的值来覆盖作为内部状态变量使用的componentInfo。但Child自定义组件并不能感知到componentInfo从外部进行了初始化,这不利于自定义组件内部状态的管理。因此推出@Local装饰器表示组件的内部状态。

@Local装饰器说明

@Local变量装饰器说明
装饰器参数无。
可装饰的变量类型Object、class、string、number、boolean、enum等基本类型以及Array、Date、Map、Set等内嵌类型。支持null、undefined以及联合类型。
装饰变量的初始值必须本地初始化,不允许外部传入初始化。

@Local装饰变量传递

传递规则说明
从父组件初始化@Local装饰的变量仅允许本地初始化,无法从外部传入初始化。
初始化子组件@Local装饰的变量可以初始化子组件中@Param装饰的变量。

观察@Local装饰变量变化

使用@Local装饰的变量具有观察变化的能力。当装饰的变量发生变化时,会触发该变量绑定的UI组件刷新

  • 当装饰的变量类型为boolean、string、number时,可以观察到对变量赋值的变化

  • @Local装饰的变量类型为null、undefined以及联合类型,变量类型改变后,UI会随之刷新。如count类型为number | undefined,初始count值为number类型,将count值变为undefined类型,UI会随之刷新。

  • 当装饰的变量类型为类对象时,仅可以观察到对类对象整体赋值的变化,无法直接观察到对类成员属性赋值的变化,对类成员属性的观察依赖@ObservedV2和@Trace装饰器。注意,API version 19之前,@Local无法和@Observed装饰的类实例对象混用。API version 19及以后,支持部分状态管理V1V2混用能力,允许@Local和@Observed同时使用,详情见状态管理V1V2混用文档。

    class RawObject { public name: string; constructor(name: string) { this.name = name; } } @ObservedV2 class ObservedObject { @Trace public name: string; constructor(name: string) { this.name = name; } } @Entry @ComponentV2 struct Index { @Local rawObject: RawObject = new RawObject('rawObject'); @Local observedObject: ObservedObject = new ObservedObject('observedObject'); build() { Column() { Text(`${this.rawObject.name}`) Text(`${this.observedObject.name}`) Button('change object') .onClick(() => { // 对类对象整体的修改均能观察到 this.rawObject = new RawObject('new rawObject'); this.observedObject = new ObservedObject('new observedObject'); }) Button('change name') .onClick(() => { // @Local不具备观察类对象属性的能力,因此对rawObject.name的修改无法观察到 this.rawObject.name = 'new rawObject name'; // 由于ObservedObject的name属性被@Trace装饰,因此对observedObject.name的修改能被观察到 this.observedObject.name = 'new observedObject name'; }) } } }
  • 当装饰简单类型数组时,可以观察到数组整体或数组项的变化

  • 当装饰的变量是嵌套类或对象数组时,@Local无法观察深层对象属性的变化。对深层对象属性的观测依赖@ObservedV2与@Trace装饰器。

  • 当装饰内置类型时,可以观察到变量整体赋值及API调用带来的变化

    类型可观察变化的API
    Arraypush, pop, shift, unshift, splice, copyWithin, fill, reverse, sort
    DatesetFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds
    Mapset, clear, delete
    Setadd, clear, delete

@Local使用限制

@Local装饰器存在以下使用限制:

  • @Local装饰器只能在@ComponentV2装饰的自定义组件中使用,否则编译时报错。

  • @Local装饰的变量表示组件内部状态,不允许从外部传入初始化,否则编译时报错。

@Local与@State对比

@Local与@State的用法、功能对比如下:

用法@State@Local
参数无。无。
从父组件初始化可选。不允许外部初始化。
观察能力能观测变量本身以及一层的成员属性,无法深度观测能观测变量本身,深度观测依赖@Trace装饰器。
数据传递可以作为数据源和子组件中状态变量同步。可以作为数据源和子组件中状态变量同步。

使用场景

观测对象整体变化

被@ObservedV2与@Trace装饰的类对象实例,具有深度观测对象属性的能力。使用@Local装饰对象,可以达到观测对象本身变化的效果。例子参考华为中级课程——@Local——观测对象整体变化

装饰Array类型变量

当装饰的对象是Array时,可以观察到Array整体的赋值,同时可以通过调用Array的接口push, pop, shift, unshift, splice, copyWithin, fill, reverse, sort更新Array中的数据。同时,数组中某个元素的直接赋值也可以监测到。华为中级课程——@Local——装饰Array类型变量

装饰Date类型变量

当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds更新Date的属性。华为中级课程——@Local——装饰Date类型变量

装饰Map类型变量

当装饰的对象是Map时,可以观察到对Map整体的赋值,同时可以通过调用Map的接口set, clear, delete更新Map中的数据。华为中级课程——@Local——装饰Map类型变量

装饰Set类型变量

当装饰的对象是Set时,可以观察到对Set整体的赋值,同时可以通过调用Set的接口add, clear, delete更新Set中的数据。华为中级课程——@Local——装饰Set类型变量

联合类型

@Local支持null、undefined以及联合类型。在下面的示例中,count类型为number | undefined,初始count值为number类型,将count值变为undefined类型,UI会随之刷新。华为中级课程——@Local——联合类型

常见问题

在状态管理V2中使用animateTo动画效果异常

animateTo暂不支持直接在状态管理V2中动画前改变值。

@Entry @ComponentV2 struct Index { @Local w: number = 50; // 宽度 @Local h: number = 50; // 高度 @Local message: string = 'Hello'; build() { Column() { Button('change size') .margin(20) .onClick(() => { // 在执行动画前,存在额外的修改 this.w = 100; this.h = 100; this.message = 'Hello World'; this.getUIContext().animateTo({ duration: 1000 }, () => { this.w = 200; this.h = 200; this.message = 'Hello ArkUI'; }) }) Column() { Text(`${this.message}`) } .backgroundColor('#ff17a98d') .width(this.w) .height(this.h) } } }

上述代码中,开发者预期的动画效果是:绿色矩形从长宽100变为200,字符串从Hello World变为Hello ArkUI。但由于当前animateTo与V2的刷新机制不兼容,执行动画前的额外修改未生效,实际显示的动画效果是:绿色矩形从长宽50变为200,字符串从Hello变为Hello ArkUI。

API version 22开始,可以使用applySync接口实现预期的显示效果。

import { UIUtils } from '@kit.ArkUI'; @Entry @ComponentV2 struct Index { @Local w: number = 50; // 宽度 @Local h: number = 50; // 高度 @Local message: string = 'Hello'; build() { Column() { Button('change size') .margin(20) .onClick(() => { // 在执行动画前,存在额外的修改 UIUtils.applySync(() => { this.w = 100; this.h = 100; this.message = 'Hello World'; }) this.getUIContext().animateTo({ duration: 1000 }, () => { this.w = 200; this.h = 200; this.message = 'Hello ArkUI'; }) }) Column() { Text(`${this.message}`) } .backgroundColor('#ff17a98d') .width(this.w) .height(this.h) } } }

原理为使用applySync接口同步刷新闭包函数内的状态变量变化,再执行原来的动画达成预期的效果。

http://www.jsqmd.com/news/294765/

相关文章:

  • 鸿蒙中级课程笔记2—状态管理V2—@Param
  • 鸿蒙中级课程笔记2—状态管理V2—@Once、@Event
  • 2026广安种植牙优质机构推荐榜 高性价比之选
  • 深入 Pinia 工作原理:响应式核心、持久化机制与缓存策略 - 教程
  • 构建AI Agent的自适应学习系统
  • 软件测试之单元测试
  • 京城爱加陪诊官方电话声明
  • 如何高效阅读学术文献:硕士研究生完全指南
  • windows版中间件启动 - 详解
  • 实用指南:我在CSDN学MYSQL之----数据库基本概念和基本知识(上)
  • 从0到1!AI提示工程架构师助力智能营销腾飞
  • 华为MetaERP实现智能高效排产的核心是通过人工智能、大数据、数字孪生等技术与传统ERP生产计划模块深度融合,构建动态优化、实时响应的排产体系
  • 一文读懂AI产品经理:职责、技能与学习路径全攻略,如何成为AI产品经理?
  • 收藏级干货:DeepSeek Engram架构解析:大模型语言理解的新思路
  • 知识图谱如何提升大模型性能?WeKnora实现原理与代码解析
  • 大模型训练项目如何落地:完整流程与实战技巧
  • AI产品经理vs传统产品经理:大模型时代必备技能与学习路线
  • DeepSeek MODEL1架构级跃迁:从Transformer到状态空间模型的革命性突破
  • 大模型新架构STEM:静态稀疏化提升效率与稳定性,代码示例全解析【收藏必看】
  • LLM微调实战教程:从零开始使用LLaMA Factory打造专业大模型,附完整代码+部署指南
  • day1-vue
  • 2026南充正规房产中介推荐榜
  • 乘风破浪,遇见未来新能源汽车(Electric Vehicle)之理性认知特斯拉安全机制,不是万能的
  • 2026年酷路泽改装优质品牌推荐指南 还原质感升级
  • 巴菲特的投资智慧与资本增值
  • 我的nextjs 16应用是会部署到vercel的,我有必要通过vite来压缩和包装一层吗?
  • AIBP-GEO优化系统:让每一次AI回答都成为您的品牌广告!
  • 树链剖分笔记
  • 大数据领域分布式计算在电商行业的应用
  • MAF快速入门(13)常见智能体编排模式