news 2026/6/13 23:14:32

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙中级课程笔记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接口同步刷新闭包函数内的状态变量变化,再执行原来的动画达成预期的效果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/11 19:59:35

构建AI Agent的自适应学习系统

构建AI Agent的自适应学习系统 关键词:AI Agent、自适应学习系统、机器学习、强化学习、神经网络 摘要:本文旨在深入探讨构建AI Agent的自适应学习系统这一前沿技术领域。通过详细阐述自适应学习系统的核心概念、算法原理、数学模型,结合项目实战案例,展示如何实现一个高效…

作者头像 李华
网站建设 2026/6/11 17:03:51

搭建终身学习系统时,AI应用架构师容易犯哪些错?(避坑指南)

AI应用架构师搭建终身学习系统的10个常见坑与避坑指南 副标题:从数据管道到模型部署的实践教训 摘要/引言 在AI从“静态工具”转向“动态系统”的今天,终身学习(Lifelong Learning) 已成为企业保持AI竞争力的核心能力——它让模型…

作者头像 李华
网站建设 2026/6/12 19:02:36

前端萌新别慌!30分钟搞懂CSS阴影:text-shadow和box-shadow实

前端萌新别慌!30分钟搞懂CSS阴影:text-shadow和box-shadow实 前端萌新别慌!30分钟搞懂CSS阴影:text-shadow和box-shadow实战指南先别急着写代码,咱先吐槽五分钟先整点能跑的,把士气提上来text-shadow&#…

作者头像 李华
网站建设 2026/6/11 17:05:26

指针进阶:二级指针与指针的指针的应用场景

指针进阶:二级指针与指针的指针的应用场景 在C指针学习中,二级指针(又称指针的指针)是从基础指针迈向进阶的关键节点。前文我们了解到,一级指针存储的是普通变量的内存地址,而二级指针的核心是“存储一级指…

作者头像 李华
网站建设 2026/6/11 17:06:19

AI智能体完全指南:无需编程基础,四步打造专属AI助手

本文详解AI智能体搭建方法,从入门到进阶,包括四步创建流程、个性化设置、知识库运用和指令迭代技巧。文章强调将AI视为协作者而非工具,根据场景选择适合的大模型,并提供多个国内免费平台推荐。无需编程基础,即可打造专…

作者头像 李华