diff --git a/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md b/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md index bd93409725adec4fe76af6d4c15eeb0d4f0bd2d5..7df90501a582c02e796a5eb61a73013dc14335ee 100644 --- a/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md +++ b/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md @@ -162,6 +162,26 @@ class ClassB { this.a = a; } } + +@Observed +class ClassD { + public c: ClassC; + + constructor(c: ClassC) { + this.c = c; + } +} + +@Observed +class ClassC extends ClassA { + public k: number; + + constructor(k: number) { + // 调用父类方法对k进行处理 + super(k); + this.k = k; + } +} ``` @@ -169,60 +189,64 @@ class ClassB { ```ts @Component -struct ViewA { - label: string = 'ViewA1'; - @ObjectLink a: ClassA; +struct ViewC { + label: string = 'ViewC1'; + @ObjectLink c: ClassC; build() { Row() { - Button(`ViewA [${this.label}] this.a.c=${this.a.c} +1`) - .onClick(() => { - this.a.c += 1; - }) - } + Column() { + Text(`ViewC [${this.label}] this.a.c = ${this.c.c}`) + .fontColor('#ffffffff') + .backgroundColor('#ff3fc4c4') + .height(50) + .borderRadius(25) + Button(`ViewC: this.c.c add 1`) + .backgroundColor('#ff7fcf58') + .onClick(() => { + this.c.c += 1; + console.log('this.c.c:' + this.c.c) + }) + } + .width(300) } } +} @Entry @Component struct ViewB { @State b: ClassB = new ClassB(new ClassA(0)); - + @State child : ClassD = new ClassD(new ClassC(0)); build() { Column() { - ViewA({ label: 'ViewA #1', a: this.b.a }) - ViewA({ label: 'ViewA #2', a: this.b.a }) - - Button(`ViewB: this.b.a.c+= 1`) - .onClick(() => { - this.b.a.c += 1; - }) - Button(`ViewB: this.b.a = new ClassA(0)`) + ViewC({ label: 'ViewC #3', c: this.child.c}) + Button(`ViewC: this.child.c.c add 10`) + .backgroundColor('#ff7fcf58') .onClick(() => { - this.b.a = new ClassA(0); - }) - Button(`ViewB: this.b = new ClassB(ClassA(0))`) - .onClick(() => { - this.b = new ClassB(new ClassA(0)); + this.child.c.c += 10 + console.log('this.child.c.c:' + this.child.c.c) }) } } } ``` +被@Observed装饰的ClassC类,可以观测到继承基类的属性的变化。 + ViewB中的事件句柄: -- this.b.a = new ClassA(0) 和this.b = new ClassB(new ClassA(0)): 对\@State装饰的变量b和其属性的修改。 +- this.child.c = new ClassA(0) 和this.b = new ClassB(new ClassA(0)): 对\@State装饰的变量b和其属性的修改。 -- this.b.a.c = ... :该变化属于第二层的变化,[@State](arkts-state.md#观察变化)无法观察到第二层的变化,但是ClassA被\@Observed装饰,ClassA的属性c的变化可以被\@ObjectLink观察到。 +- this.child.c.c = ... :该变化属于第二层的变化,[@State](arkts-state.md#观察变化)无法观察到第二层的变化,但是ClassA被\@Observed装饰,ClassA的属性c的变化可以被\@ObjectLink观察到。 -ViewA中的事件句柄: +ViewC中的事件句柄: -- this.a.c += 1:对\@ObjectLink变量a的修改,将触发Button组件的刷新。\@ObjectLink和\@Prop不同,\@ObjectLink不拷贝来自父组件的数据源,而是在本地构建了指向其数据源的引用。 +- this.c.c += 1:对\@ObjectLink变量a的修改,将触发Button组件的刷新。\@ObjectLink和\@Prop不同,\@ObjectLink不拷贝来自父组件的数据源,而是在本地构建了指向其数据源的引用。 - \@ObjectLink变量是只读的,this.a = new ClassA(...)是不允许的,因为一旦赋值操作发生,指向数据源的引用将被重置,同步将被打断。 diff --git a/zh-cn/application-dev/quick-start/arkts-prop.md b/zh-cn/application-dev/quick-start/arkts-prop.md index 6cd73cad08ad60920ea090fd764fac4ccc1f3300..b9c26caecc72796493cb68c3ad44a9bc63b55222 100644 --- a/zh-cn/application-dev/quick-start/arkts-prop.md +++ b/zh-cn/application-dev/quick-start/arkts-prop.md @@ -25,6 +25,7 @@ | 装饰器参数 | 无 | | 同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件\@Prop装饰的变量,子组件\@Prop变量的修改不会同步到父组件的状态变量上。嵌套类型的场景请参考[观察变化](#观察变化)。 | | 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
支持Date类型。
支持类型的场景请参考[观察变化](#观察变化)。
必须指定类型。
**说明** :
不支持Length、ResourceStr、ResourceColor类型,Length,ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。
在父组件中,传递给\@Prop装饰的值不能为undefined或者null,反例如下所示。
CompA ({ aProp: undefined })
CompA ({ aProp: null })
\@Prop和[数据源](arkts-state-management-overview.md#基本概念)类型需要相同,有以下三种情况:
- \@Prop装饰的变量和\@State以及其他装饰器同步时双方的类型必须相同,示例请参考[父组件@State到子组件@Prop简单数据类型同步](#父组件state到子组件prop简单数据类型同步)。
- \@Prop装饰的变量和\@State以及其他装饰器装饰的数组的项同步时 ,\@Prop的类型需要和\@State装饰的数组的数组项相同,比如\@Prop : T和\@State : Array<T>,示例请参考[父组件@State数组中的项到子组件@Prop简单数据类型同步](#父组件state数组项到子组件prop简单数据类型同步);
- 当父组件状态变量为Object或者class时,\@Prop装饰的变量和父组件状态变量的属性类型相同,示例请参考[从父组件中的@State类对象属性到@Prop简单类型的同步](#从父组件中的state类对象属性到prop简单类型的同步)。 | +| 嵌套传递层数 | 在组件复用场景,建议@Prop深度嵌套数据不要超过5层,嵌套太多会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收),引起性能问题,此时更建议使用[\@ObjectLink](arkts-observed-and-objectlink.md)。如果子组件的数据不想同步回父组件,建议采用@Reusable中的aboutToReuse,实现父组件向子组件传递数据,具体用例请参考[组件复用场景](arkts-state-management-best-practices.md)。 | | 被装饰变量的初始值 | 允许本地初始化。 | @@ -32,7 +33,7 @@ | 传递/访问 | 说明 | | --------- | ---------------------------------------- | -| 从父组件初始化 | 如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp去初始化子组件中的\@Prop变量。 | +| 从父组件初始化 | 如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新。只有状态变量才能触发UI刷新)、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp去初始化子组件中的\@Prop变量。 | | 用于初始化子组件 | \@Prop支持去初始化子组件中的常规变量、\@State、\@Link、\@Prop、\@Provide。 | | 是否支持组件外访问 | \@Prop装饰的变量是私有的,只能在组件内访问。 | @@ -50,7 +51,7 @@ \@Prop装饰的数据可以观察到以下变化。 -- 当装饰的类型是允许的类型,即Object、class、string、number、boolean、enum类型都可以观察到的赋值变化。 +- 当装饰的类型是允许的类型,即Object、class、string、number、boolean、enum类型都可以观察到赋值的变化。 ```ts // 简单类型 @@ -88,29 +89,7 @@ this.title.value = 'Hi' this.title.a.value = 'ArkUi' ``` -对于嵌套场景,如果装饰的class是被\@Observed装饰的,可以观察到class属性的变化。 - -``` -@Observed -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' -// 可以观察到ClassA属性的变化,因为ClassA被@Observed装饰this.title.a.value = 'ArkUi' -``` +对于嵌套场景,如果class是被\@Observed装饰的,可以观察到class属性的变化,示例请参考[@Prop嵌套场景](#@Prop嵌套场景)。 当装饰的类型是数组的时候,可以观察到数组本身的赋值、添加、删除和更新。 @@ -568,4 +547,88 @@ struct MainProgram { } } ``` + +### \@Prop嵌套场景 + +在嵌套场景下,每一层都要用@Observed装饰,且每一层都要被@Prop接收,这样才能观察到嵌套场景。 + +```ts +// 以下是嵌套类对象的数据结构。 +@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嵌套场景的数据结构。 + +```ts + +@Entry +@Component +struct Parent { + @State votes: ClassB = new ClassB('Hello', new ClassA('world')) + + build() { + Column() { + Button('change') + .onClick(() => { + this.votes.name = "aaaaa" + this.votes.a.title = "wwwww" + }) + Child({ vote: this.votes }) + } + + } +} + +@Component +struct Child { + @Prop vote: ClassB + 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 + build() { + Column() { + Text(this.vote1.title).fontSize(36).fontColor(Color.Red).margin(50) + .onClick(() => { + this.vote1.title = 'Bye Bye' + }) + } + } +} +``` + \ No newline at end of file diff --git a/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md b/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md index 884049f962138d509baf86dccb75b3066eff90a8..a99d4c79d546534729132d6753472f18cb231c0d 100644 --- a/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md +++ b/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md @@ -61,7 +61,7 @@ | \@Provide传递/访问 | 说明 | | -------------- | ---------------------------------------- | -| 从父组件初始化和更新 | 可选,允许父组件中常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量装饰变量初始化子组件\@Provide。 | +| 从父组件初始化和更新 | 可选,允许父组件中常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新,只有状态变量才能触发UI刷新)、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量装饰变量初始化子组件\@Provide。 | | 用于初始化子组件 | 允许,可用于初始化\@State、\@Link、\@Prop、\@Provide。 | | 和父组件同步 | 否。 | | 和后代组件同步 | 和\@Consume双向同步。 | diff --git a/zh-cn/application-dev/quick-start/arkts-state-management-best-practices.md b/zh-cn/application-dev/quick-start/arkts-state-management-best-practices.md index 24b1660cb6eb7175cd5c5a0ea2e01b1752f16ece..2b43630dabee7a29420404f80c963cb8b99d08f7 100644 --- a/zh-cn/application-dev/quick-start/arkts-state-management-best-practices.md +++ b/zh-cn/application-dev/quick-start/arkts-state-management-best-practices.md @@ -1022,4 +1022,345 @@ struct CompA { .width(200).height(500) } } +``` + +## 组件复用场景 + +子组件通过@Prop接收父组件传递的数据,如果嵌套的层数过多,会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收),引起性能问题。下面给出5层@Prop嵌套传递数据的不推荐用法及通过@Reusable实现父组件向子组件传递数据的推荐用法。 + +### 不推荐用法 + +```ts +// 以下是嵌套类对象的数据结构。 +@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; + } +} + +@Observed +class ClassC { + public name: string; + public b: ClassB; + + constructor(name: string, b: ClassB) { + this.name = name; + this.b = b; + } +} + +@Observed +class ClassD { + public name: string; + public c: ClassC; + + constructor(name: string, c: ClassC) { + this.name = name; + this.c = c; + } +} + +@Observed +class ClassE { + public name: string; + public d: ClassD; + + constructor(name: string, d: ClassD) { + this.name = name; + this.d = d; + } +} + +``` + +以下组件层次结构呈现的是@Prop嵌套场景的数据结构。 + +```ts +@Entry +@Component +struct Parent { + @State vote: ClassE = new ClassE('Hi', new ClassD('OpenHarmony', new ClassC('Hello', new ClassB('World', new ClassA('Peace'))))) + + build() { + Column() { + Button('change') + .onClick(() => { + this.vote.name = "Hello" + }) + Child({ voteOne: this.vote }) + } + } +} + +@Component +struct Child { + @Prop voteOne: ClassE + build() { + Column() { + Text(this.voteOne.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteOne.name:' + this.voteOne.name); + this.voteOne.name = 'Bye' + }) + ChildOne({voteTwo:this.voteOne.d}) + } + } +} + +@Component +struct ChildOne { + @Prop voteTwo: ClassD + build() { + Column() { + Text(this.voteTwo.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteTwo.name:' + this.voteTwo.name); + this.voteTwo.name = 'Bye Bye' + }) + ChildTwo({voteThree:this.voteTwo.c}) + } + } +} + +@Component +struct ChildTwo { + @Prop voteThree: ClassC + build() { + Column() { + Text(this.voteThree.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteThree.name:' + this.voteThree.name); + this.voteThree.name = 'Bye Bye Bye' + }) + ChildThree({voteFour:this.voteThree.b}) + } + } +} + +@Component +struct ChildThree { + @Prop voteFour: ClassB + build() { + Column() { + Text(this.voteFour.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteFour.name:' + this.voteFour.name); + this.voteFour.name = 'Bye Bye Bye Bye' + }) + ChildFour({voteFive:this.voteFour.a}) + } + } +} + +@Component +struct ChildFour { + @Prop voteFive: ClassA + build() { + Column() { + Text(this.voteFive.title).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteFive.title:' + this.voteFive.title); + this.voteFive.title = 'Bye Bye Bye Bye Bye' + }) + } + } +} +``` + +### 推荐用法 + +当在组件复用场景时,父组件向子组件传递数据,子组件变化不会同步给父组件,推荐使用aboutToResue。 + +```ts +// 以下是嵌套类对象的数据结构。 +@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; + } +} + +@Observed +class ClassC { + public name: string; + public b: ClassB; + + constructor(name: string, b: ClassB) { + this.name = name; + this.b = b; + } +} + +@Observed +class ClassD { + public name: string; + public c: ClassC; + + constructor(name: string, c: ClassC) { + this.name = name; + this.c = c; + } +} + +@Observed +class ClassE { + public name: string; + public d: ClassD; + + constructor(name: string, d: ClassD) { + this.name = name; + this.d = d; + } +} + +``` + +以下组件层次结构呈现的是@Reusable组件复用场景的数据结构。 + +```ts +@Entry +@Component +struct Parent { + @State vote: ClassE = new ClassE('Hi', new ClassD('OpenHarmony', new ClassC('Hello', new ClassB('World', new ClassA('Peace'))))) + + build() { + Column() { + Button('change') + .onClick(() => { + this.vote.name = "Hello" + }) + .reuseId(Child.name) + Child({voteOne: this.vote}) + } + } +} + +@Reusable +@Component +struct Child { + @State voteOne: ClassE = new ClassE('voteOne', new ClassD('OpenHarmony', new ClassC('Hello', new ClassB('World', new ClassA('Peace'))))) + aboutToReuse(params){ + this.voteOne = params + + } + build() { + Column() { + Text(this.voteOne.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.error('this.voteOne.name:' + this.voteOne.name); + this.voteOne.name = 'Bye' + }) + .reuseId(ChildOne.name) + ChildOne({voteTwo: this.voteOne.d}) + } + } +} + +@Reusable +@Component +struct ChildOne { + @State voteTwo: ClassD = new ClassD('voteTwo', new ClassC('Hello', new ClassB('World', new ClassA('Peace')))) + aboutToReuse(params){ + this.voteTwo = params + } + build() { + Column() { + Text(this.voteTwo.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.error('this.voteTwo.name:' + this.voteTwo.name); + this.voteTwo.name = 'Bye Bye' + }) + .reuseId(ChildTwo.name) + ChildTwo({voteThree: this.voteTwo.c}) + } + } +} + +@Reusable +@Component +struct ChildTwo { + @State voteThree: ClassC = new ClassC('voteThree', new ClassB('World', new ClassA('Peace'))) + aboutToReuse(params){ + this.voteThree = params + + } + build() { + Column() { + Text(this.voteThree.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteThree.name:' + this.voteThree.name); + this.voteThree.name = 'Bye Bye Bye' + }) + .reuseId(ChildThree.name) + ChildThree({voteFour: this.voteThree.b}) + } + } +} + +@Reusable +@Component +struct ChildThree { + @State voteFour: ClassB = new ClassB('voteFour', new ClassA('Peace')) + aboutToReuse(params){ + this.voteFour = params + + } + build() { + Column() { + Text(this.voteFour.name).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteFour.name:' + this.voteFour.name); + this.voteFour.name = 'Bye Bye Bye Bye' + }) + .reuseId(ChildFour.name) + ChildFour({voteFive: this.voteFour.a}) + } + } +} + +@Reusable +@Component +struct ChildFour { + @State voteFive: ClassA = new ClassA('voteFive') + aboutToReuse(params){ + this.voteFive = params + + } + build() { + Column() { + Text(this.voteFive.title).fontSize(24).fontColor(Color.Red).margin(50) + .onClick(() => { + console.log('this.voteFive.title:' + this.voteFive.title); + this.voteFive.title = 'Bye Bye Bye Bye Bye' + }) + } + } +} ``` \ No newline at end of file diff --git a/zh-cn/application-dev/quick-start/arkts-state.md b/zh-cn/application-dev/quick-start/arkts-state.md index 3ed13539bb0f6262ab34e4c448f5fe618ff24d0c..c1fd5dd5cd17569604028957edb6e96cd27d7ec9 100644 --- a/zh-cn/application-dev/quick-start/arkts-state.md +++ b/zh-cn/application-dev/quick-start/arkts-state.md @@ -37,7 +37,7 @@ | 传递/访问 | 说明 | | ------------------ | ------------------------------------------------------------ | -| 从父组件初始化 | 可选,从父组件初始化或者本地初始化。如果从父组件初始化将会覆盖本地初始化。
支持父组件中常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量,初始化子组件的\@State。 | +| 从父组件初始化 | 可选,从父组件初始化或者本地初始化。如果从父组件初始化将会覆盖本地初始化。
支持父组件中常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新,只有状态变量才能触发UI刷新)、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量,初始化子组件的\@State。 | | 用于初始化子组件 | \@State装饰的变量支持初始化子组件的常规变量、\@State、\@Link、\@Prop、\@Provide。 | | 是否支持组件外访问 | 不支持,只能在组件内访问。 | diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001653986573.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001653986573.png old mode 100644 new mode 100755 index 575d5ea86ae4a3cc7bde1f290558223d23a8e3b7..fb2017c34b46aa4ce884105bc852c0011ba3e1f7 Binary files a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001653986573.png and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001653986573.png differ