1.概述
@Prop装饰的变量和父组件建立单向的同步关系:
@Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
当数据源更改时,@Prop装饰的变量都会更新,并且会覆盖本地所有更改。因此,数值的同步是父组件到子组件(所属组件),子组件数值的变化不会同步到父组件
2.限制条件
@Prop装饰变量时会进行深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array外,都会丢失类型。例如PixelMap等通过NAPI提供的复杂类型,由于有部分实现在Native侧,因此无法在ArkTS侧通过深拷贝获得完整的数据。
@Prop装饰器不能在@Entry装饰的自定义组件中使用。
3.观察变化
3.1.以下情况可以观察到=>
- 当装饰的类型是允许的类型,即Object、class、string、number、boolean、enum类型都可以观察到赋值的变化。
- 当装饰的类型是Object或者class复杂类型时,可以观察到第一层的属性的变化,属性即Object.keys(observedObject)返回的所有属性;对于嵌套场景,如果class是被@Observed装饰的,可以观察到class属性的变化
- 当装饰的类型是数组的时候,可以观察到数组本身的赋值和数组项的添加、删除和更新。
- 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。
- 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。
3.2.对于@State和@Prop的同步场景:
使用父组件中@State变量的值初始化子组件中的@Prop变量。当@State变量变化时,该变量值也会同步更新至@Prop变量。
@Prop装饰的变量的修改不会影响其数据源@State装饰变量的值。
除了@State,数据源也可以用@Link或@Prop装饰,对@Prop的同步机制是相同的。
数据源和@Prop变量的类型需要相同,@Prop允许简单类型和class类型。
当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。
4.框架行为
要理解@Prop变量值初始化和更新机制,有必要了解父组件和拥有@Prop变量的子组件初始渲染和更新流程。
初始渲染:
- 执行父组件的build()函数将创建子组件的新实例,将数据源传递给子组件;
- 初始化子组件@Prop装饰的变量。
更新:
- 子组件@Prop更新时,更新仅停留在当前子组件,不会同步回父组件;
- 当父组件的数据源更新时,子组件的@Prop装饰的变量将被来自父组件的数据源重置,所有@Prop装饰的本地的修改将被父组件的更新覆盖。
说明
@Prop装饰的数据更新依赖其所属自定义组件的重新渲染,所以在应用进入后台后,@Prop无法刷新,推荐使用@Link代替。
5.简单示例,方便理解
@Component
struct CountDownComponent {
@Prop count: number = 0;
costOfOneAttempt: number = 1;build() {
Column() {
if (this.count > 0) {
Text(`You have ${this.count} Nuggets left`)
} else {
Text('Game over!')
}
// @Prop装饰的变量不会同步给父组件
Button(`Try again`).onClick(() => {
this.count -= this.costOfOneAttempt;
})
}
}
}@Entry
@Component
struct ParentComponent {
@State countDownStartValue: number = 10;build() {
Column() {
Text(`Grant ${this.countDownStartValue} nuggets to play.`)
// 父组件的数据源的修改会同步给子组件
Button(`+1 - Nuggets in New Game`).onClick(() => {
this.countDownStartValue += 1;
})
// 父组件的修改会同步给子组件
Button(`-1 - Nuggets in New Game`).onClick(() => {
this.countDownStartValue -= 1;
})CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
}
}
}