赞
踩
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。
@Prop装饰的变量和父组件建立单向的同步关系:
@Prop变量装饰器 | 说明 |
---|---|
装饰器参数 | 无 |
同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上 |
允许装饰的变量类型 | string、number、boolean、enum类型。 不支持any,不允许使用undefined和null。 必须指定类型。 在父组件中,传递给@Prop装饰的值不能为undefined或者null,反例如下所示。 CompA ({ aProp: undefined }) CompA ({ aProp: null }) @Prop和数据源类型需要相同,有以下三种情况(数据源以@State为例):
|
被装饰变量的初始值 | 允许本地初始化。 |
传递/访问 | 说明 |
---|---|
从父组件初始化 | 如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量、@State、@Link、@Prop、@Provide、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp去初始化子组件中的@Prop变量。 |
用于初始化子组件 | @Prop支持去初始化子组件中的常规变量、@State、@Link、@Prop、@Provide。 |
是否支持组件外访问 | @Prop装饰的变量是私有的,只能在组件内访问。 |
图1 初始化规则图示
@Prop装饰的数据可以观察到以下变化。
- // 简单类型
- @Prop count: number;
- // 赋值的变化可以被观察到
- this.count = 1;
对于@State和@Prop的同步场景:
要理解@Prop变量值初始化和更新机制,有必要了解父组件和拥有@Prop变量的子组件初始渲染和更新流程。
以下示例是@State到子组件@Prop简单数据同步,父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中@Prop装饰的count,点击“Try again”,count的修改仅保留在CountDownComponent 不会同步给父组件CountDownComponent。
ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。
- @Component
- struct CountDownComponent {
- @Prop count: number;
- 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 })
- }
- }
- }
在上面的示例中:
父组件中@State如果装饰的数组,其数组项也可以初始化@Prop。以下示例中父组件Index中@State装饰的数组arr,将其数组项初始化子组件Child中@Prop装饰的value。
- @Component
- struct Child {
- @Prop value: number;
-
- build() {
- Text(`${this.value}`)
- .fontSize(50)
- .onClick(()=>{this.value++})
- }
- }
-
- @Entry
- @Component
- struct Index {
- @State arr: number[] = [1,2,3];
-
- build() {
- Row() {
- Column() {
- Child({value: this.arr[0]})
- Child({value: this.arr[1]})
- Child({value: this.arr[2]})
-
- Divider().height(5)
-
- ForEach(this.arr,
- item => {
- Child({value: item})
- },
- item => item.toString()
- )
- Text('replace entire arr')
- .fontSize(50)
- .onClick(()=>{
- // 两个数组都包含项“3”。
- this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];
- })
- }
- }
- }
- }
初始渲染创建6个子组件实例,每个@Prop装饰的变量初始化都在本地拷贝了一份数组项。子组件onclick事件处理程序会更改局部变量值。
假设我们点击了多次,所有变量的本地取值都是“7”。
- 7
- 7
- 7
- ----
- 7
- 7
- 7
单击replace entire arr后,屏幕将显示以下信息,为什么?
- 3
- 4
- 5
- ----
- 7
- 4
- 5
如果图书馆有一本图书和两位用户,每位用户都可以将图书标记为已读,此标记行为不会影响其它读者用户。从代码角度讲,对@Prop图书对象的本地更改不会同步给图书馆组件中的@State图书对象。
- class Book {
- public title: string;
- public pages: number;
- public readIt: boolean = false;
-
- constructor(title: string, pages: number) {
- this.title = title;
- this.pages = pages;
- }
- }
-
- @Component
- struct ReaderComp {
- @Prop title: string;
- @Prop readIt: boolean;
-
- build() {
- Row() {
- Text(this.title)
- Text(`... ${this.readIt ? 'I have read' : 'I have not read it'}`)
- .onClick(() => this.readIt = true)
- }
- }
- }
-
- @Entry
- @Component
- struct Library {
- @State book: Book = new Book('100 secrets of C++', 765);
-
- build() {
- Column() {
- ReaderComp({ title: this.book.title, readIt: this.book.readIt })
- ReaderComp({ title: this.book.title, readIt: this.book.readIt })
- }
- }
- }
为了支持@Component装饰的组件复用场景,@Prop支持本地初始化,这样可以让@Prop是否与父组件建立同步关系变得可选。当且仅当@Prop有本地初始化时,从父组件向子组件传递@Prop的数据源才是可选的。
下面的示例中,子组件包含两个@Prop变量:
- @Component
- struct MyComponent {
- @Prop customCounter: number;
- @Prop customCounter2: number = 5;
-
- build() {
- Column() {
- Row() {
- Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
- }
-
- Row() {
- Button('Click to change locally !').width(480).height(60).margin({ top: 10 })
- .onClick(() => {
- this.customCounter2++
- })
- }.height(100).width(480)
-
- Row() {
- Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
- }
- }
- }
- }
-
- @Entry
- @Component
- struct MainProgram {
- @State mainCounter: number = 10;
-
- build() {
- Column() {
- Row() {
- Column() {
- Button('Click to change number').width(480).height(60).margin({ top: 10, bottom: 10 })
- .onClick(() => {
- this.mainCounter++
- })
- }
- }
-
- Row() {
- Column()
- // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。
- MyComponent({ customCounter: this.mainCounter })
- // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
- MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
- }.width('40%')
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。