网站推广工具网络,郑州工作,无锡设计网站找哪家,做宝宝衣服的网站Prop装饰的变量可以和父组件建立单向的同步关系。Prop装饰的变量是可变的#xff0c;但是变化不会同步回其父组件。
说明#xff1a;
从API version 9开始#xff0c;该装饰器支持在ArkTS卡片中使用。
概述
Prop装饰的变量和父组件建立单向的同步关系#xff1a;
● P…Prop装饰的变量可以和父组件建立单向的同步关系。Prop装饰的变量是可变的但是变化不会同步回其父组件。
说明
从API version 9开始该装饰器支持在ArkTS卡片中使用。
概述
Prop装饰的变量和父组件建立单向的同步关系
● Prop变量允许在本地修改但修改后的变化不会同步回父组件。
● 当数据源更改时Prop装饰的变量都会更新并且会覆盖本地所有更改。因此数值的同步是父组件到子组件所属组件)子组件数值的变化不会同步到父组件。
装饰器使用规则说明
Prop变量装饰器说明装饰器参数无同步类型单向同步对父组件状态变量值的修改将同步给子组件Prop装饰的变量子组件Prop变量的修改不会同步到父组件的状态变量上。嵌套类型的场景请参考 观察变化 。允许装饰的变量类型Object、class、string、number、boolean、enum类型以及这些类型的数组。不支持any不支持简单类型和复杂类型的联合类型不允许使用undefined和null。支持Date类型。支持类型的场景请参考观察变化。必须指定类型。说明 不支持Length、ResourceStr、ResourceColor类型LengthResourceStr、ResourceColor为简单类型和复杂类型的联合类型。在父组件中传递给Prop装饰的值不能为undefined或者null反例如下所示。CompA ({ aProp: undefined })CompA ({ aProp: null }) Prop和数据源类型需要相同有以下三种情况- Prop装饰的变量和State以及其他装饰器同步时双方的类型必须相同示例请参考父组件State到子组件Prop简单数据类型同步。- Prop装饰的变量和State以及其他装饰器装饰的数组的项同步时 Prop的类型需要和State装饰的数组的数组项相同比如Prop : T和State : Array示例请参考 父组件State数组中的项到子组件Prop简单数据类型同步- 当父组件状态变量为Object或者class时Prop装饰的变量和父组件状态变量的属性类型相同示例请参考 从父组件中的State类对象属性到Prop简单类型的同步 。嵌套传递层数在组件复用场景建议Prop深度嵌套数据不要超过5层嵌套太多会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收)引起性能问题此时更建议使用 ObjectLink 。如果子组件的数据不想同步回父组件建议采用Reusable中的aboutToReuse实现父组件向子组件传递数据具体用例请参考 组件复用场景。被装饰变量的初始值允许本地初始化。
变量的传递/访问规则说明
| 传递/访问 | 说明 | | 从父组件初始化 | 如果本地有初始化则是可选的。没有的话则必选支持父组件中的常规变量常规变量对Prop赋值只是数值的初始化常规变量的变化不会触发UI刷新。只有状态变量才能触发UI刷新、State、Link、Prop、Provide、Consume、ObjectLink、StorageLink、StorageProp、LocalStorageLink和LocalStorageProp去初始化子组件中的Prop变量。 | | 用于初始化子组件 | Prop支持去初始化子组件中的常规变量、State、Link、Prop、Provide。 | | 是否支持组件外访问 | Prop装饰的变量是私有的只能在组件内访问。 |
图1 初始化规则图示 观察变化和行为表现
观察变化
Prop装饰的数据可以观察到以下变化。
● 当装饰的类型是允许的类型即Object、class、string、number、boolean、enum类型都可以观察到赋值的变化。
// 简单类型
Prop count: number;
// 赋值的变化可以被观察到
this.count 1;
// 复杂类型
Prop count: Model;
// 可以观察到赋值的变化
this.title new Model(Hi);当装饰的类型是Object或者class复杂类型时可以观察到第一层的属性的变化属性即Object.keys(observedObject)返回的所有属性
class ClassA {public value: string;constructor(value: string) {this.value value;}
}
class Model {public value: string;public a: ClassA;constructor(value: string, a: ClassA) {this.value value;this.a a;}
}Prop title: Model;
// 可以观察到第一层的变化
this.title.value Hi
// 观察不到第二层的变化
this.title.a.value ArkUi对于嵌套场景如果class是被Observed装饰的可以观察到class属性的变化示例请参考 Prop嵌套场景 。
当装饰的类型是数组的时候可以观察到数组本身的赋值、添加、删除和更新。
// State装饰的对象为数组时
Prop title: string[]
// 数组自身的赋值可以观察到
this.title [1]
// 数组项的赋值可以观察到
this.title[0] 2
// 删除数组项可以观察到
this.title.pop()
// 新增数组项可以观察到
this.title.push(3)对于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的属性。
Component
struct DateComponent {Prop selectedDate: Date new Date();build() {Column() {Button(child update the new date).margin(10).onClick(() {this.selectedDate new Date(2023-09-09)})Button(child increase the year by 1).onClick(() {this.selectedDate.setFullYear(this.selectedDate.getFullYear() 1)})DatePicker({start: new Date(1970-1-1),end: new Date(2100-1-1),selected: this.selectedDate})}}
}Entry
Component
struct ParentComponent {State parentSelectedDate: Date new Date(2021-08-08);build() {Column() {Button(parent update the new date).margin(10).onClick(() {this.parentSelectedDate new Date(2023-07-07)})Button(parent increase the day by 1).margin(10).onClick(() {this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() 1)})DatePicker({start: new Date(1970-1-1),end: new Date(2100-1-1),selected: this.parentSelectedDate})DateComponent({selectedDate:this.parentSelectedDate})}}
}框架行为
要理解Prop变量值初始化和更新机制有必要了解父组件和拥有Prop变量的子组件初始渲染和更新流程。
1. 初始渲染
a. 执行父组件的build()函数将创建子组件的新实例将数据源传递给子组件
b. 初始化子组件Prop装饰的变量。
2. 更新
a. 子组件Prop更新时更新仅停留在当前子组件不会同步回父组件
b. 当父组件的数据源更新时子组件的Prop装饰的变量将被来自父组件的数据源重置所有Prop装饰的本地的修改将被父组件的更新覆盖。
使用场景
父组件State到子组件Prop简单数据类型同步
以下示例是State到子组件Prop简单数据同步父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中Prop装饰的count点击“Try again”count的修改仅保留在CountDownComponent 不会同步给父组件ParentComponent。
ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。
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 })}}
}在上面的示例中
1. CountDownComponent子组件首次创建时其Prop装饰的count变量将从父组件State装饰的countDownStartValue变量初始化
2. 按“1”或“-1”按钮时父组件的State装饰的countDownStartValue值会变化这将触发父组件重新渲染在父组件重新渲染过程中会刷新使用countDownStartValue状态变量的UI组件并单向同步更新CountDownComponent子组件中的count值
3. 更新count状态变量值也会触发CountDownComponent的重新渲染在重新渲染过程中评估使用count状态变量的if语句条件this.count 0并执行true分支中的使用count状态变量的UI组件相关描述来更新Text组件的UI显示
4. 当按下子组件CountDownComponent的“Try again”按钮时其Prop变量count将被更改但是count值的更改不会影响父组件的countDownStartValue值
5. 父组件的countDownStartValue值会变化时父组件的修改将覆盖掉子组件CountDownComponent中count本地的修改。
父组件State数组项到子组件Prop简单数据类型同步
父组件中State如果装饰的数组其数组项也可以初始化Prop。以下示例中父组件Index中State装饰的数组arr将其数组项初始化子组件Child中Prop装饰的value。
Component
struct Child {Prop value: number 0;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: void) {Child({value: item})},(item: string) 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● 在子组件Child中做的所有的修改都不会同步回父组件Index组件所以即使6个组件显示都为7但在父组件Index中this.arr保存的值依旧是[1,2,3]。
● 点击replace entire arrthis.arr[0] 1成立将this.arr赋值为[3, 4, 5]
● 因为this.arr[0]已更改Child({value: this.arr[0]})组件将this.arr[0]更新同步到实例Prop装饰的变量。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情况也类似。
● this.arr的更改触发ForEach更新this.arr更新的前后都有数值为3的数组项[3, 4, 5] 和[1, 2, 3]。根据diff机制数组项“3”将被保留删除“1”和“2”的数组项添加为“4”和“5”的数组项。这就意味着数组项“3”的组件不会重新生成而是将其移动到第一位。所以“3”对应的组件不会更新此时“3”对应的组件数值为“7”ForEach最终的渲染结果是“7”“4”“5”。
从父组件中的State类对象属性到Prop简单类型的同步
如果图书馆有一本图书和两位用户每位用户都可以将图书标记为已读此标记行为不会影响其它读者用户。从代码角度讲对Prop图书对象的本地更改不会同步给图书馆组件中的State图书对象。
在此示例中图书类可以使用Observed装饰器但不是必须的只有在嵌套结构时需要此装饰器。这一点我们会在 从父组件中的State数组项到Prop class类型的同步 说明。
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 book: Book new Book(, 0);build() {Row() {Text(this.book.title)Text(...has${this.book.pages} pages!)Text(...${this.book.readIt ? I have read : I have not read it}).onClick(() this.book.readIt true)}}
}Entry
Component
struct Library {State book: Book new Book(100 secrets of C, 765);build() {Column() {ReaderComp({ book: this.book })ReaderComp({ book: this.book })}}
}从父组件中的State数组项到Prop class类型的同步
在下面的示例中更改了State 修饰的allBooks数组中Book对象上的属性但点击“Mark read for everyone”无反应。这是因为该属性是第二层的嵌套属性State装饰器只能观察到第一层属性不会观察到此属性更改所以框架不会更新ReaderComp。
let nextId: number 1;// Observed
class Book {public id: number;public title: string;public pages: number;public readIt: boolean false;constructor(title: string, pages: number) {this.id nextId;this.title title;this.pages pages;}
}Component
struct ReaderComp {Prop book: Book new Book(, 1);build() {Row() {Text(this.book.title)Text(...has${this.book.pages} pages!)Text(...${this.book.readIt ? I have read : I have not read it}).onClick(() this.book.readIt true)}}
}Entry
Component
struct Library {State allBooks: Book[] [new Book(100 secrets of C, 765), new Book(Effective C, 651), new Book(The C programming language, 1765)];build() {Column() {Text(librarys all time favorite)ReaderComp({ book: this.allBooks[2] })Divider()Text(Books on loaan to a reader)ForEach(this.allBooks, (book: Book) {ReaderComp({ book: book })},(book: Book) book.id.toString())Button(Add new).onClick(() {this.allBooks.push(new Book(The C Standard Library, 512));})Button(Remove first book).onClick(() {this.allBooks.shift();})Button(Mark read for everyone).onClick(() {this.allBooks.forEach((book) book.readIt true)})}}
}需要使用Observed装饰class BookBook的属性将被观察。 需要注意的是Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系即ReaderComp中的Prop book的修改不会同步给父组件Library。而父组件只会在数值有更新的时候和上一次状态的对比才会触发UI的重新渲染。
Observed
class Book {public id: number;public title: string;public pages: number;public readIt: boolean false;constructor(title: string, pages: number) {this.id nextId;this.title title;this.pages pages;}
}Observed装饰的类的实例会被不透明的代理对象包装此代理可以检测到包装对象内的所有属性更改。如果发生这种情况此时代理通知PropProp对象值被更新。
Prop本地初始化不和父组件同步
为了支持Component装饰的组件复用场景Prop支持本地初始化这样可以让Prop是否与父组件建立同步关系变得可选。当且仅当Prop有本地初始化时从父组件向子组件传递Prop的数据源才是可选的。
下面的示例中子组件包含两个Prop变量
● Prop customCounter没有本地初始化所以需要父组件提供数据源去初始化Prop并当父组件的数据源变化时Prop也将被更新
● Prop customCounter2有本地初始化在这种情况下Prop依旧允许但非强制父组件同步数据源给Prop。
Component
struct MyComponent {Prop customCounter: number 0;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(180).height(60).margin({ top: 10 }).onClick(() {this.customCounter2})}.height(100).width(180)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 })}}}}
}Prop嵌套场景
在嵌套场景下每一层都要用Observed装饰且每一层都要被Prop接收这样才能观察到嵌套场景。
// 以下是嵌套类对象的数据结构。
Observed
class ClassA {public title: string;constructor(title: string) {this.title title;}
}Observed
class ClassB {public name: string;public a: ClassA;constructor(name: string, a: ClassA) {this.name name;this.a a;}
}以下组件层次结构呈现的是Prop嵌套场景的数据结构。
Entry
Component
struct Parent {State votes: ClassB new ClassB(Hello, new ClassA(world))build() {Column() {Button(change).onClick(() {this.votes.name aaaaathis.votes.a.title wwwww})Child({ vote: this.votes })}}
}Component
struct Child {Prop vote: ClassB new ClassB(, new ClassA());build() {Column() {Text(this.vote.name).fontSize(36).fontColor(Color.Red).margin(50).onClick(() {this.vote.name Bye})Text(this.vote.a.title).fontSize(36).fontColor(Color.Blue).onClick(() {this.vote.a.title openHarmony})Child1({vote1:this.vote.a})}}
}Component
struct Child1 {Prop vote1: ClassA new ClassA();build() {Column() {Text(this.vote1.title).fontSize(36).fontColor(Color.Red).margin(50).onClick(() {this.vote1.title Bye Bye})}}
}如果大家想更加深入的学习 OpenHarmony 开发的内容不妨可以参考以下相关学习文档进行学习助你快速提升自己
OpenHarmony 开发环境搭建https://qr18.cn/CgxrRy 《OpenHarmony源码解析》https://qr18.cn/CgxrRy
搭建开发环境Windows 开发环境的搭建Ubuntu 开发环境搭建Linux 与 Windows 之间的文件共享……
系统架构分析https://qr18.cn/CgxrRy
构建子系统启动流程子系统分布式任务调度子系统分布式通信子系统驱动子系统…… OpenHarmony 设备开发学习手册https://qr18.cn/CgxrRy OpenHarmony面试题内含参考答案https://qr18.cn/CgxrRy