提交 0104de1c 编写于 作者: W WangYanchao0418

fixed d4e0b2eb from https://gitee.com/WangYanchao0418/docs_2/pulls/22583

对状态管理文档的修改 Signed-off-by: WangYanchao0418 <wangyanchao16@huawei.com>
上级 c0b1e42a
......@@ -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`)
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.a.c += 1;
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(...)是不允许的,因为一旦赋值操作发生,指向数据源的引用将被重置,同步将被打断。
......
......@@ -25,6 +25,7 @@
| 装饰器参数 | 无 |
| 同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件\@Prop装饰的变量,子组件\@Prop变量的修改不会同步到父组件的状态变量上。嵌套类型的场景请参考[观察变化](#观察变化)。 |
| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。<br/>不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。<br/>支持Date类型。<br/>支持类型的场景请参考[观察变化](#观察变化)。<br/>必须指定类型。<br/>**说明** :<br/>不支持Length、ResourceStr、ResourceColor类型,Length,ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。<br/>在父组件中,传递给\@Prop装饰的值不能为undefined或者null,反例如下所示。<br/>CompA&nbsp;({&nbsp;aProp:&nbsp;undefined&nbsp;})<br/>CompA&nbsp;({&nbsp;aProp:&nbsp;null&nbsp;})<br/>\@Prop和[数据源](arkts-state-management-overview.md#基本概念)类型需要相同,有以下三种情况:<br/>-&nbsp;\@Prop装饰的变量和\@State以及其他装饰器同步时双方的类型必须相同,示例请参考[父组件@State到子组件@Prop简单数据类型同步](#父组件state到子组件prop简单数据类型同步)。<br/>-&nbsp;\@Prop装饰的变量和\@State以及其他装饰器装饰的数组的项同步时 ,\@Prop的类型需要和\@State装饰的数组的数组项相同,比如\@Prop&nbsp;:&nbsp;T和\@State&nbsp;:&nbsp;Array&lt;T&gt;,示例请参考[父组件@State数组中的项到子组件@Prop简单数据类型同步](#父组件state数组项到子组件prop简单数据类型同步);<br/>-&nbsp;当父组件状态变量为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_check-->
\ No newline at end of file
......@@ -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双向同步。 |
......
......@@ -1023,3 +1023,344 @@ struct CompA {
}
}
```
## 组件复用场景
子组件通过@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
......@@ -37,7 +37,7 @@
| 传递/访问 | 说明 |
| ------------------ | ------------------------------------------------------------ |
| 从父组件初始化 | 可选,从父组件初始化或者本地初始化。如果从父组件初始化将会覆盖本地初始化。<br/>支持父组件中常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量,初始化子组件的\@State。 |
| 从父组件初始化 | 可选,从父组件初始化或者本地初始化。如果从父组件初始化将会覆盖本地初始化。<br/>支持父组件中常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新,只有状态变量才能触发UI刷新)\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量,初始化子组件的\@State。 |
| 用于初始化子组件 | \@State装饰的变量支持初始化子组件的常规变量、\@State、\@Link、\@Prop、\@Provide。 |
| 是否支持组件外访问 | 不支持,只能在组件内访问。 |
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册