HarmonyOS鸿蒙Next V2状态管理 @Local 和 @Param
HarmonyOS鸿蒙Next V2状态管理 @Local 和 @Param
HarmonyOS Next V2 状态管理 @Local 和 @Param
@Local 背景
[@Local](/user/Local) 是 harmony 应用开发中的v2版本中对标 [@State](/user/State) 的状态管理修饰器,它解决了 [@State](/user/State) 对状态变量更改的检测混乱的问题:
[@State](/user/State)修饰的状态变量 可以是组件内部自己定义的[@State](/user/State)修饰的状态 也可以由外部父组件传递
这样就导致了状态数据来源不唯一,在大型项目中会引发难易检测和维护状态的问题。如以下代码:
@Entry
@Component
struct Index {
[@State](/user/State) num: number = 100
build() {
Column() {
Text("父组件的数据 " + this.num)
Son({ num: this.num }) // 这里就报错啦
Son()
}
.height('100%')
.width('100%')
}
}
@ComponentV2 // 此处调整为 @ComponentV2
struct Son {
// 此处调整为 [@Local](/user/Local)
[@Local](/user/Local) num: number = 0
build() {
Column() {
Button(`子组件 ${this.num}`)
.onClick(() => {
this.num++
})
}
}
}
@Local 基本使用
[@Local](/user/Local) 的出现就是为了解决这一类问题
[@Local](/user/Local)只能用在@Componentv2修饰的组件上- 被
[@Local](/user/Local)装饰的变量无法从外部初始化(无法由父组件传递进来),因此必须在组件内部进行初始化
我们对上面代码稍作修改
@Entry
@Component
struct Index {
[@State](/user/State) num: number = 100
build() {
Column() {
Text("父组件的数据 " + this.num)
Son({ num: this.num }) // 这里就报错啦
Son()
}
.height('100%')
.width('100%')
}
}
@ComponentV2 // 此处调整为 @ComponentV2
struct Son {
// 此处调整为 [@Local](/user/Local)
[@Local](/user/Local) num: number = 0
build() {
Column() {
Button(`子组件 ${this.num}`)
.onClick(() => {
this.num++
})
}
}
}
@Local与@State对比
| @State | @Local | |
|---|---|---|
| 参数 | 无。 | 无。 |
| 从父组件初始化 | 可选。 | 不允许外部初始化。 |
| 观察能力 | 能观测变量本身以及一层的成员属性,无法深度观测。 | 能观测变量本身,深度观测依赖@Trace装饰器。 |
| 数据传递 | 可以作为数据源和子组件中状态变量同步。 | 可以作为数据源和子组件中状态变量同步。 |
@Local 特别注意
[@Local](/user/Local)支持观测 number、boolean、string、Object、class 等基本类型以及 Array、Set、Map、Date 等内嵌类型。[@Local](/user/Local)的观测能力仅限于被装饰的变量本身。当装饰简单类型时,能够观测到对变量的赋值;当装饰对象类型时,仅能观测到对对象整体的赋值;当装饰数组类型时,能观测到数组整体以及数组元素项的变化;当装饰 Array、Set、Map、Date 等内嵌类型时,可以观测到通过 API 调用带来的变化。
@Params
[@Params](/user/Params) 主要表示 子组件 接收父组件传递的数据。可以和 [@Local](/user/Local) 搭配一起使用
@Params 背景
在V1版本的状态管理修饰符中,可以用来处理 父子传参的技术有:
- 普通属性,不需要特别的修饰符 , 不具备单向同步
@Prop单向同步,不能监听深层次属性的改变,也不能做到双向同步@Link可以做到双向同步,但是不能监听深层次属性的改变,而且不能直接用在 列表渲染技术 - ForEach 中@ObjectLink可以做到双向同步,但是必须和@Observed搭配使用 ,而且只能用在自定义组件上
1. 普通属性
普通属性,不需要特别的修饰符 , 不具备单向同步
@Entry
@Component
struct Index {
[@State](/user/State) num: number = 100
build() {
Column() {
// 父组件传递过去的数据
Son({ num: this.num })
.onClick(() => {
this.num++
console.log("", this.num)
})
}
.height('100%')
.width('100%')
}
}
@Component
struct Son {
num: number = 0
build() {
Column() {
Button(`子组件 ${this.num}`)
}
}
}
2. @Prop 单向同步
@Prop 单向同步
- 不能监听深层次属性的改变
- 也不能做到双向同步
在上面代码基础上 加入 @Prop,可以检测到基本类型数据的更新
@Component
struct Son {
@Prop num: number = 0
但是无法检测深层次属性的改变,如
class Animal {
dog: Dog = {
age: 100
}
}
class Dog {
age: number = 100
}
@Entry
@Component
struct Index {
[@State](/user/State)
animal: Animal = new Animal()
build() {
Column() {
// 父组件传递过去的数据
Son({ dog: this.animal.dog })
.onClick(() => {
this.animal.dog.age++
console.log("", this.animal.dog.age)
})
}
.height('100%')
.width('100%')
}
}
@Component
struct Son {
@Prop dog: Dog
build() {
Column() {
Button(`子组件 ${this.dog.age}`)
}
}
}
3. @Link 双向同步
可以做到双向同步,但是
- 不能监听深层次属性的改变
- 而且不能直接用在 列表渲染技术 - ForEach 中
以下代码演示这个效果
class Dog {
age: number = 100
}
@Entry
@Component
struct Index {
[@State](/user/State)
dogList: Dog [] = [new Dog(), new Dog(), new Dog(), new Dog()]
build() {
Column() {
ForEach(this.dogList, (item: Dog) => {
// 此处会报错 Assigning the attribute 'item' to the '@Link' decorated attribute 'dog' is not allowed. <ArkTSCheck>
Son({ dog: item })
.onClick(() => {
item.age++
console.log("", item.age)
})
})
}
.height('100%')
.width('100%')
}
}
@Component
struct Son {
@Link dog: Dog
build() {
Column() {
Button(`子组件 ${this.dog.age}`)
}
}
}
4. @ObjectLink
@ObjectLink 可以做到双向同步,但是必须和 @Observed 搭配使用 ,而且只能用在自定义组件上
小结
可以看到,如果都是使用 v1版本的这一套 父子传参的技术,是十分复杂难易直接上手使用的。
@Params 介绍
Param表示组件从外部传入的状态,使得父子组件之间的数据能够进行同步:
[@Param](/user/Param)装饰的变量支持本地初始化,但是不允许在组件内部直接修改变量本身。如果不本地初始化,那么必须加入@Require[@Param](/user/Param)可以做到单向同步[@Param](/user/Param)可以检测深层次属性的修改,但是该修改在数据源上必须是整体对象的更新[@Params](/user/Params)如果也想要深度监听单个属性的修改,那么需要使用@ObservedV2和[@Trace](/user/Trace)
以下代码主要演示: [@Param](/user/Param) 可以检测深层次属性的修改,但是该修改在数据源上必须是整体对象的更新**
class Person {
age: number = 100
}
@Entry
@ComponentV2
struct Index {
[@Local](/user/Local)
person: Person = new Person()
build() {
Column() {
Son({ age: this.person.age })
.onClick(() => {
this.person.age++
console.log("", this.person.age)
if (this.person.age === 105) {
const p = new Person()
p.age = 200
// 整体更新,子组件可以感知到
this.person = p
}
})
}
.height('100%')
.width('100%')
}
}
@ComponentV2
struct Son {
// 要么设置 @Require 表示父组件必须传递数据
// 要么设置 默认值
@Require [@Param](/user/Param) age: number
build() {
Column() {
Button(`子组件 ${this.age}`)
}
}
}
总结
[@Local](/user/Local)可以看成是[@State](/user/State)的替代 ,单独表示组件内部的状态[@Params](/user/Params)可以看成@Prop@Link@ObjectLink的替代,更加严谨[@Local](/user/Local)和[@Params](/user/Params)搭配一起使用,都只能用在@Componentv2修饰的自定义组件上
更多关于HarmonyOS鸿蒙Next V2状态管理 @Local 和 @Param的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next V2中,@Local和@Param是用于状态管理的装饰器。@Local用于标记组件内部的状态,这些状态只能在组件内部访问和修改,不会影响到其他组件。@Param用于标记通过父组件传递进来的状态,这些状态可以在子组件中访问和修改,并且会同步到父组件中。这两个装饰器帮助开发者在组件间管理和传递状态,确保状态的可控性和一致性。
更多关于HarmonyOS鸿蒙Next V2状态管理 @Local 和 @Param的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙NEXT V2中,状态管理通过@Local和@Param注解来实现。
@Local用于声明组件内部的状态,适用于仅在组件内部使用的数据。例如:
@Local
private count: number = 0;
@Param用于声明组件从外部接收的参数,适用于父组件传递的数据。例如:
@Param
private message: string = '';
@Local状态的变化不会影响外部组件,而@Param参数的变化则可能触发父组件的重新渲染。合理使用这两个注解,可以有效管理组件的状态和参数传递。

