状态管理更新到 v2 版本,使用 @ComponentV2 装饰自定义组件,在 @ComponentV2 版本中仅能使用 @Local、@Param、@Once、@Event、@Provider、@Consumer 等装饰器。
@Local
@Local 状态变量表示组件内部的状态, 必须在组件内部初始化, 不允许从外部初始化。
- @Local装饰器只能在@ComponentV2装饰的自定义组件中使用。
- @Local 仅能观察到状态变量的整体赋值,对于类对象类型的状态变量,无法直接观察到对类成员属性赋值的变化,需要结合 @ObservedV2和 @Trace
typescript
@Entry
@ComponentV2
struct LocalPage {
@Local skill: string = 'Android';
@Local user: LocalUser = new LocalUser('Android')
@Local observedUser: ObservedLocalUser = new ObservedLocalUser('Android')
build() {
Column() {
Text('message: ' + this.skill)
Text('user.skill: ' + this.user.skill)
Text('observedUser.skill: ' + this.observedUser.skill)
Button('change').onClick((event: ClickEvent) => {
this.skill = 'Kotlin' // 有效刷新,可以观察到状态变量的整体赋值,
this.user = new LocalUser('Kotlin') // 有效刷新,可以观察到状态变量的整体赋值,
this.observedUser = new ObservedLocalUser('Kotlin') // 有效刷新,可以观察到状态变量的整体赋值,
})
Button('change property').onClick((event: ClickEvent) => {
this.user.skill = 'ArkUI' // 无效刷新,@Local无法直接观察到状态变量深层属性的变化,需要结合 @ObservedV2,@Trace
this.observedUser.skill = 'ArkUI' // 有效刷新,结合 @ObservedV2,@Trace
})
}
.height('100%')
.width('100%')
}
}
export class LocalUser {
skill: string
constructor(skill: string) {
this.skill = skill;
}
}
@ObservedV2
export class ObservedLocalUser {
@Trace skill: string
constructor(skill: string) {
this.skill = skill;
}
}
@Param
@Param表示组件从外部传入的状态,使得父子组件之间的数据能够进行同步.
- @Param装饰的变量支持本地初始化,但是不允许在组件内部直接修改变量本身。
- 被@Param装饰的变量能够在初始化自定义组件时从外部传入,当数据源也是状态变量时,数据源的修改会同步给@Param。
- 对于复杂类型如类对象,@Param会接受数据源的引用。在组件内可以修改类对象中的属性,该修改会同步到数据源。
typescript
@Entry
@ComponentV2
struct ParamPage {
@Local message: string = 'Hello World';
@Local user: User = new User('Android', 15)
build() {
Column({ space: 6 }) {
Text(this.message).onClick(() => this.message = 'parent set')
Text(this.user.name + " -- " + this.user.age).onClick(() => this.user = new User('parent', 12))
Button('change').onClick((event: ClickEvent) => {
this.message = 'harmony' // 有效刷新,可以观察到状态变量的修改
this.user = new User('harmony', 12) // 有效刷新, 可以观察到状态变量的整体赋值
})
Button('change property').onClick((event: ClickEvent) => {
this.user.name = 'arkui' // 有效刷新,因为结合了 @ObservedV2 和 @Trace
})
Blank().height(10)
ChildParam({ msg: this.message, user: this.user })
}
.height('100%')
.width('100%')
}
}
@ComponentV2
struct ChildParam {
@Param msg: string = 'child init'
@Param user: User = new User('child init', 1)
build() {
Column() {
Text(this.msg).fontSize(20).onClick(() => {
// this.msg = 'compose' // 报错,不允许修改 @Param 状态变量,若需要修改@Param变量,需要结合 @Event
})
Text(this.user.name + " - " + this.user.age).fontSize(20).onClick(() => {
// this.user = new User('',12) // 报错,不允许修改 @Param 状态变量
this.user.name = 'Compose' // 可以修改 @Param 状态变量的属性,修改可以同步给父组件
})
}
}
}
@ObservedV2
class User {
@Trace name: string
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
@Event
由于@Param装饰的变量在本地无法更改,使用@Event装饰器装饰回调方法并调用,可以实现更改数据源的变量,再通过@Local的同步机制,将修改同步回@Param,以此达到主动更新@Param装饰变量的效果
- @Event装饰的回调方法中参数以及返回值由自己任意定义。
- 当@Event未被外部初始化,但本地有默认值时,会使用本地默认的函数进行处理
less
@Entry
@ComponentV2
struct EventPage {
@Local message: string = 'Hello World';
@Local user: EventUser = new EventUser('Kotlin')
build() {
Column() {
Text(this.message)
Text(this.user.name)
Button('change').onClick((event: ClickEvent) => {
this.message = 'Hello HarmonyOS'
this.user = new EventUser('ArkTS')
})
Button('change property').onClick((event: ClickEvent) => {
this.user.name = 'arkUI'
})
ChildEvent({
msg: this.message,
user: this.user,
onMsgChange: (msg) => {
this.message = msg
},
onUserChange: (user) => {
this.user = user
}
})
}
.height('100%')
.width('100%')
}
}
@ComponentV2
struct ChildEvent {
@Param msg: string = ''
@Param user: EventUser = new EventUser('')
@Event onMsgChange: (msg: string) => void = () => {
}
@Event onUserChange: (user: EventUser) => void = () => {
}
build() {
Column() {
Text(this.msg).fontSize(20).onClick(() => {
this.onMsgChange('child set')
})
Text(this.user.name).onClick(() => {
this.onUserChange(new EventUser('child user'))
})
}
}
}
class EventUser {
name: string
constructor(name: string) {
this.name = name
}
}
@Once
@Once装饰器仅在变量初始化时接受外部传入值进行初始化,当后续数据源更改时,不会将修改同步给子组件:
- @Once必须搭配@Param装饰器使用,单独使用或搭配其他装饰器使用都是不允许的。
- @Once不影响@Param的观测能力,仅针对数据源的变化做拦截。
typescript
@Entry
@ComponentV2
struct OncePage {
@Local message: string = 'Hello World';
build() {
Column() {
Text(this.message).onClick(() => this.message = 'parent')
ChildOnce({ msg: this.message })
}
.height('100%')
.width('100%')
}
}
@ComponentV2
struct ChildOnce {
@Once @Param msg: string = ''
build() {
Text(this.msg)
}
}
@Monitor
@Monitor 和 @Watch 类似,都是用于监听变量的变化, 当监听的变量变化时会触发对应的回调函数
typescript
import { promptAction } from '@kit.ArkUI';
import { User } from '../../models/User';
@Entry
@ComponentV2
struct MonitorPage {
@Local message: string = 'Hello World';
@Local user: User = new User('Android', 12)
@Monitor('message', 'user.name')
onChange() {
promptAction.showToast({ message: 'onChange: ' + this.message })
promptAction.showToast({ message: 'user.name: ' + this.user.name })
}
build() {
Column() {
Text(this.message).fontSize(30).onClick(() => this.message = 'android')
Text(this.user.name + '-' + this.user.age).onClick(()=> this.user.name = 'new name')
}
.height('100%')
.width('100%')
}
}