目录
前言
在鸿蒙 ArkTS 开发中,组件的状态管理是核心能力之一。随着 ArkTS 0.8+ 版本的演进,V2 组件体系引入了新的状态管理装饰器,其中 @Local 是最常用的一种。本文将全面介绍 @Local 的作用、使用方法、优势及实际案例。
这里需要说明的是:
从API version 12开始,在@ComponentV2装饰的自定义组件中支持使用@Local装饰器。
从API version 12开始,该装饰器支持在元服务中使用。
1.什么是@Local
@Local 是 ArkTS V2 组件体系中用于声明组件内部私有状态的装饰器。它类似于V1的 @State,但在V2中功能更精细,性能更高。@Local 声明的状态只属于当前组件,外部无法直接访问或修改,保证了组件内部状态的封装性和独立性。
使用@Local 非常简单,你只需要在组件的类成员上加上装饰器即可:
@ComponentV2
struct CounterComponent {
@Local count: number = 0; // 内部状态
build() {
Column() {
Text(`当前计数:${this.count}`)
.fontSize(24)
.padding(20)
Row() {
Button('增加')
.onClick(() => { this.count++ })
Button('减少')
.onClick(() => { this.count-- })
}.justifyContent(FlexAlign.SpaceAround)
}
}
}
在上面的代码中:
@Local count: number = 0:定义组件的私有状态count,初始值为0。
当count 发生变化时,组件会自动重新渲染。
外部无法直接访问 count,保证状态的封装性。
2.@Local的特点与优势
1.私有状态
@Local声明的状态仅属于当前组件,保证了组件内部的状态封装。其他组件或父组件无法直接访问或修改它。
2.响应式
组件会自动监听@Local 修饰的状态,当状态发生变化时,组件会触发重新渲染,无需手动刷新。
3.与V2生命周期兼容
@Local与V2组件的生命周期和性能优化机制兼容,支持冻结非活跃组件的状态监听,提高性能。
4.类型安全
使用TypeScript 的类型系统,@Local 支持类型推导和静态检查,减少运行时错误。
3.详细用法
使用@Local装饰的变量具有被观测变化的能力。当装饰的变量发生变化时,会触发该变量绑定的UI组件刷新。
1. boolean、string、number
当装饰的变量类型为boolean、string、number时,可以观察到对变量赋值的变化。
@ComponentV2
struct TodoListComponent {
@Local todos: string[] = []
addTodo(todo: string) {
this.todos = [...this.todos, todo]; // 替换式赋值,触发渲染
}
build() {
Column() {
ForEach(this.todos, (item, index) => {
ListItem() {
Text(item)
}
}, item => item)
Button('添加任务').onClick(() => this.addTodo('新任务'))
}
}
}
2. 类对象
当装饰的变量类型为类对象时,仅可以观察到对类对象整体赋值的变化,无法直接观察到对类成员属性赋值的变化,对类成员属性的观察依赖@ObservedV2和@Trace装饰器。注意,API version 19之前,@Local无法和@Observed装饰的类实例对象混用。API version 19及以后,支持部分状态管理V1V2混用能力,允许@Local和@Observed同时使用,详情见状态管理V1V2混用文档。
如果我们定义了一个RawObject对象:
class RawObject {
name: string;
constructor(name: string) {
this.name = name;
}
}
@ObservedV2
class ObservedObject {
@Trace name: string;
constructor(name: string) {
this.name = name;
}
}
@Entry
@ComponentV2
struct LocalExample01 {
@Local rawObject: RawObject = new RawObject("rawObject");
@Local observedObject: ObservedObject = new ObservedObject("observedObject");
build() {
NavDestination(){
Column() {
Row(){
Column(){
Text(`${this.rawObject.name}`).margin({top:20})
Text(`${this.observedObject.name}`).margin({top:20})
Button("change object")
.onClick(() => {
// 对类对象整体的修改均能观察到
this.rawObject = new RawObject("new rawObject");
this.observedObject = new ObservedObject("new observedObject");
}).margin({top:20})
Button("change name")
.onClick(() => {
// @Local不具备观察类对象属性的能力,因此对rawObject.name的修改无法观察到
this.rawObject.name = "new rawObject name";
// 由于ObservedObject的name属性被@Trace装饰,因此对observedObject.name的修改能被观察到
this.observedObject.name = "new observedObject name";
}).margin({top:20})
}.backgroundColor(Color.White).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).margin({top:20,bottom:20})
}.margin({top:20,left:20,right:20}).borderColor(Color.Gray).width('100%').borderRadius(5).backgroundColor(Color.White).justifyContent(FlexAlign.Center)
}
.padding({
left: '12vp',
right: '12vp',
bottom: '24vp'
})
.backgroundColor('#F1F3F5')
.width('100%')
.height('100%')
}.title("Local修饰类对象")
}
}
3.单类型数组
当装饰简单类型数组时,可以观察到数组整体或数组项的变化。
以下面的代码为例,点击按钮之后,UI中始终数组元素的Text实时刷新。
@Entry
@ComponentV2
struct LocalExample02 {
@Local numArr: number[] = [1,2,3,4,5]; // 使用@Local装饰一维数组变量
@Local dimensionTwo: number[][] = [[1,2,3],[4,5,6]]; // 使用@Local装饰二维数组变量
build() {
NavDestination(){
Column() {
Text(`${this.numArr[0]}`)
Text(`${this.numArr[1]}`)
Text(`${this.numArr[2]}`)
Text(`${this.dimensionTwo[0][0]}`)
Text(`${this.dimensionTwo[1][1]}`)
Button("change array item") // 按钮1:修改数组中的特定元素
.onClick(() => {
this.numArr[0]++;
this.numArr[1] += 2;
this.dimensionTwo[0][0] = 0;
this.dimensionTwo[1][1] = 0;
})
Button("change whole array") // 按钮2:替换整个数组
.onClick(() => {
this.numArr = [5,4,3,2,1];
this.dimensionTwo = [[7,8,9],[0,1,2]];
})
}.justifyContent(FlexAlign.SpaceEvenly).width('100%').height('100%')
}.title("简单的数组")
}
}
4.嵌套类或对象数组
当装饰的变量是嵌套类或对象数组时,@Local无法观察深层对象属性的变化。对深层对象属性的观测依赖@ObservedV2与@Trace装饰器。
5.内置类型
当装饰内置类型时,可以观察到变量整体赋值及API调用带来的变化。
类型 | 可观测变化的API |
---|---|
Array | push, pop, shift, unshift, splice, copyWithin, fill, reverse, sort |
Date | setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds |
Map | set, clear, delete |
Set | add, clear, delete |