1# Mixing Use of Custom Components 2 3For the \@Component decorated custom components (referred to as the custom components of V1), corresponding state variable decorators (referred to as the decorators of V1), such as \@State, \@Prop, and \@Link, are provided. However, state management V1 (V1 for short) has many restrictions on the observation of nested classes. For example, you need to use \@ObjectLink to continuously disassemble nested classes so that in-depth data can be observed. Therefore, a new set of state management V2 (V2 for short) is developed in API version 12. You can declare \@ComponentV2 decorated custom components (referred to as custom components of V2) and use them with new decorators (referred to as the decorators of V2), such as \@Local and \@Param. The proposal of V2 not only compensates the deficiency of V1 in nested class observation, but also enhances some decorator functions. For example, compared with \@Watch of V1, \@Monitor of V2 can sense the changed data and obtain the data before the change. 4 5In terms of design, the code of V1 and V2 are expected to be completely isolated because V2 can do better than V1 in certain scenarios. However, from the actual perspective, the code developed in V1 have a solid foundation and it is not practical to migrate the entire code to V2 at a time. Therefore, it is allowed to use some capabilities of V2 in the code of V1 and capabilities of V1 is not completely prohibited in V2. For example, a custom component of V1 uses a custom component of V2, or V1 uses a decorator of V2. In this way, a problem of mixed use of V1 and V2 occurs. 6 7This document describes the mixed use of V1 and V2, aiming at guiding you to migrate code of V1 to V2. 8 9> **NOTE** 10> 11> State management V2 is supported since API version 12. 12 13## Overview 14 15The rules for mixing the use of V1 and V2 are as follows: 16 17* The decorators of V2 cannot be used in the custom components of V1. Otherwise, an error is reported during compilation. 18 19* When no variable is passed between components, custom components of V1 can use custom components of V2 as well as import \@ComponentV2 decorated custom components of a third party. 20 21* When variables are passed between components, such as passing variables of V1 to the custom components of V2, constraints are as follows: 22 - Variables that are not decorated by decorators in V1 (common variables) can be received only by using \@Param in V2. 23 - Variables decorated by the decorator in V1 (state variables) can be received only by using \@Param in V2 and are limited to simple data types such as boolean, number, enum, string, undefined and null. 24 25* The decorators of V1 cannot be used in the custom components of V2. Otherwise, an error is reported during compilation. 26 27* When no variable is passed between components, custom components of V2 can use custom components of V1 as well as import \@Component decorated custom components of a third party. 28 29* When variables are passed between components, such as passing variables of V2 to the custom components of V1, constraints are as follows: 30 - Variables that are not decorated by decorators in V2 (common variables) can be received by using \@State, \@Prop, and \@Provide in V1. 31 - Variables decorated by the decorator in V2 (state variables) of the built-in types, such as Array, Set, Map, and Date, are not supported in V1. 32 33## State Management Decorator Overview 34 35### Decorators of V1 36 37| Type | Decorator | 38| :----------: | :----------------------------------------------------------: | 39| Intra-component decorator| \@State, \@Prop, \@Link, \@ObjectLink, \@Provide, \@Consume, \@StorageProp, \@StorageLink, \@LocalStorageProp, \@LocalStorageLink, \@Watch| 40| Class-related decorator| \@Observed, \@Track | 41 42### Decorators of V2 43 44| Type | Decorator | 45| :----------: | :----------------------------------------------------------: | 46| Intra-component decorator| \@Local, \@Param, \@Provider, \@Consumer, \@Once, \@Event, \@Monitor, \@Computed| 47| Class-related decorator| \@ObservedV2, \@Trace, \@Type | 48 49### Data Types Supported by State Management Decorators 50 51 52 53| Type | Keyword | 54| ------------ | -------------------------------------------------- | 55| Simple type| boolean, number, enum, string, null, undefined | 56| Function type| function (supported only by \@Event, \@Monitor, and \@Computed of V2)| 57| Object type | Object | 58| Class type | Class | 59| Built-in type | Array, Map, Set, Date | 60 61 62 63## Constraints 64 65### Mixing Use of Decorators of V1 and V2 Is Forbidden 66 67**1. The decorators of V2 cannot be used in the custom components of V1.** 68 69```typescript 70@Component 71struct Child { 72 // @Param cannot be used in @Component. Otherwise, an error is reported during compilation. 73 // @Once and @Require are the extended decorators of @Param and must be used together with @Param. 74 @Param message: string = ""; 75 @Event changeMessage: (val: string) => void; // @Event cannot be used in @Component. Otherwise, an error is reported during compilation. 76 77 build() { 78 Column() { 79 Text(this.message) 80 .fontSize(50) 81 .fontWeight(FontWeight.Bold) 82 .onClick(() => { 83 this.changeMessage('world hello'); 84 }) 85 } 86 } 87} 88 89@Entry 90@Component 91struct Index { 92 @Local message: string ='Hello World'; // @Local cannot be used in @Component. Otherwise, an error is reported during compilation. 93 94 build() { 95 Column() { 96 Text(this.message) 97 .fontSize(50) 98 .fontWeight(FontWeight.Bold) 99 Divider() 100 .color(Color.Blue) 101 Child({ 102 message: this.message, 103 changeMessage: (val: string) => { 104 this.message = val; 105 } 106 }) 107 } 108 .height('100%') 109 .width('100%') 110 } 111} 112``` 113 114The intra-component decorators in V2 cannot be used in the custom components of V1. Otherwise, an error is reported during compilation. 115 116The sample code shows how \@Local, \@Param, \@Event, \@Provider, \@Consumer, \@Monitor and \@Computed decorators work. 117 118**2. The decorators of V1 cannot be used in the custom components of V2.** 119 120```typescript 121@ComponentV2 122struct Child { 123 @Prop message: string = ""; // @Prop cannot be used in @ComponentV2. Otherwise, an error is reported during compilation. 124 @Link myId: number; // @Link cannot be used in @ComponentV2. Otherwise, an error is reported during compilation. 125 126 build() { 127 Column() { 128 Text(this.message) 129 .fontSize(50) 130 .fontWeight(FontWeight.Bold) 131 .onClick(() => { 132 this.message = 'world hello'; 133 }) 134 Divider() 135 .color(Color.Blue) 136 Text(`${this.myId}`) 137 .id('HelloWorld') 138 .fontSize(50) 139 .fontWeight(FontWeight.Bold) 140 .onClick(() => { 141 this.myId++; 142 }) 143 } 144 } 145} 146 147@Entry 148@ComponentV2 149struct Index { 150 @State message: string = 'Hello World'; // @State cannot be used in @ComponentV2. Otherwise, an error is reported during compilation. 151 @State @Watch('idChange') myId: number = 1; // @Watch cannot be used in @ComponentV2. Otherwise, an error is reported during compilation. 152 153 idChange(propName: number) : void { 154 console.info(`id changed ${this.myId}`); 155 } 156 157 build() { 158 Column() { 159 Text(this.message) 160 .fontSize(50) 161 .fontWeight(FontWeight.Bold) 162 Divider() 163 .color(Color.Blue) 164 Child({ 165 message: this.message, 166 myId: this.myId 167 }) 168 } 169 .height('100%') 170 .width('100%') 171 .margin(5) 172 } 173} 174``` 175 176The intra-component decorators in V1 cannot be used in the custom components of V2. Otherwise, an error is reported during compilation. 177 178The sample code shows how \@ObjectLink, \@Provide, \@Consume, \@StorageProp, \@StorageLink, \@LocalStorageProp, and \@LocalStorageLink decorators work. 179 180### Using Multiple Decorators to Decorate the Same Variable Is Forbidden (Except \@Watch, \@Once, and \@Require) 181 182```typescript 183@Component 184struct Child { 185 @State @Prop message: string = ""; // Multiple decorators of V1 cannot decorate the same variable. Otherwise, an error is reported during compilation. 186 187 build() { 188 Column() { 189 Text(this.message) 190 .fontSize(50) 191 .fontWeight(FontWeight.Bold) 192 .onClick(() => { 193 this.message = 'world hello'; 194 }) 195 } 196 } 197} 198 199@Entry 200@ComponentV2 201struct Index { 202 @Local @Param message: string = 'Hello World'; // Multiple decorators of V2 cannot decorate the same variable. Otherwise, an error is reported during compilation. 203 204 build() { 205 Column() { 206 Text(this.message) 207 .fontSize(50) 208 .fontWeight(FontWeight.Bold) 209 Divider() 210 .color(Color.Blue) 211 Child({ 212 message: this.message 213 }) 214 } 215 .height('100%') 216 .width('100%') 217 } 218} 219``` 220 221All decorators cannot decorate the same variable except extended decorators \@Watch, \@Once, and \@Require that can be used with other decorators. 222 223## Introduction to Mixed Use 224 225### Mixing Use of Decorators of V1 and V2 226 227**1. Use the \@ObservedV2 decorated class object in a custom component of V1.** 228 229```typescript 230@ObservedV2 231class Info { 232 @Trace myId: number; // Observable. 233 name: string; // Not observable. 234 @Track trackId: number = 1; // As a decorator of V1, @Track cannot be used in @ObservedV2. Otherwise, an error is reported during compilation. Remove @Track to eliminate the error. 235 236 constructor(id?: number, name?: string) { 237 this.myId = id || 0; 238 this.name = name || 'aaa'; 239 } 240} 241 242@Observed 243class message extends Info { // Classes inherited from @ObservedV2 cannot be decorated by Observed. Otherwise, an error is reported during compilation. Remove @Observed to eliminate the error. 244} 245 246class MessageInfo extends Info { 247} 248 249@Entry 250@Component 251struct Index { 252 info1: Info = new Info(); // @ObservedV2 decorated class can be used in V1, and @Trace decorated class is observable. 253 @State info2: Info = new Info(); // @ObservedV2 decorated class cannot be decorated by the decorator of V1. Otherwise, an error is reported during compilation. Remove @State to eliminate the error. 254 255 @State messageInfo: MessageInfo = new MessageInfo(); // Classes inherited from @ObservedV2 cannot be decorated by the decorator of V1. Otherwise, an error is reported during runtime. Remove @State to eliminate the error. 256 build() { 257 Column() { 258 Text(`info1 name: ${this.info1.name}`) // name is not decorated by @Trace and is not observable. 259 .fontSize(50) 260 .fontWeight(FontWeight.Bold) 261 .onClick(() => { 262 this.info1.name += 'b'; 263 }) 264 Text(`info1 id: ${this.info1.myId}`) // myId is decorated by @Trace and is observable. 265 .fontSize(50) 266 .fontWeight(FontWeight.Bold) 267 .onClick(() => { 268 this.info1.myId += 1; 269 }) 270 Divider() 271 .color(Color.Blue) 272 Text(`info2 id: ${this.info2.myId}`) 273 .fontSize(50) 274 .fontWeight(FontWeight.Bold) 275 .onClick(() => { 276 this.info2.myId += 1; 277 }) 278 Divider() 279 .color(Color.Blue) 280 Text(`messageInfo id: ${this.messageInfo.myId}`) // A crash occurs during runtime when the class inherited from @ObservedV2 is decorated by the decorators of V1. Remove @State to eliminate the error. 281 .fontSize(50) 282 .fontWeight(FontWeight.Bold) 283 .onClick(() => { 284 this.messageInfo.myId += 1; 285 }) 286 } 287 .height('100%') 288 .width('100%') 289 .margin(5) 290 } 291} 292``` 293 294Using \@ObservedV2 must comply with the following rules: 295 296* \@ObservedV2 can decorate only Class; \@Trace and \@Type can decorate only class properties and can be used only in \@ObservedV2. 297* \@Track cannot be used in \@ObservedV2. 298* A class decorated by \@ObservedV2 cannot be directly decorated by the decorator of V1. Otherwise, an error is reported during compilation. 299* In the example, the code can be executed properly after you remove the decorator that reports error. The property change can be observed only when the class is decorated by \@Trace. 300 301**2. Use the \@Observed decorated class object in a custom component of V2.** 302 303```typescript 304@Observed 305class Info { 306 @Track myId: number; // Not observable. Only associated update caused by other property changes can be prevented. 307 name: string; // Not observable. 308 @Trace trackId: number = 1; // As a decorator of V2, @Trace cannot be used in @Observed. Otherwise, an error is reported during compilation. Remove @Trace to eliminate the error. 309 constructor(id?: number, name?: string) { 310 this.myId = id || 0; 311 this.name = name || 'aaa'; 312 } 313} 314 315@ObservedV2 316class message extends Info { // @ObservedV2 decorated class cannot inherit from @Observed. Otherwise, an error is reported during compilation. Remove @ObservedV2 to eliminate the error. 317} 318 319class MessageInfo extends Info { 320} 321 322@Entry 323@ComponentV2 324struct Index { 325 info1: Info = new Info(); // @Observed decorated class can be used in V2. 326 @Local info2: Info = new Info(); // @Observe decorated class cannot be decorated by the decorator of V2. Otherwise, an error is reported during compilation. Remove @Local to eliminate the error. 327 @Local messageInfo: MessageInfo = new MessageInfo(); 328 build() { 329 Column() { 330 Text(`info1 name: ${this.info1.name}`) 331 .fontSize(50) 332 .fontWeight(FontWeight.Bold) 333 .onClick(() => { 334 this.info1.name += 'b'; 335 }) 336 Text(`info1 id: ${this.info1.myId}`) 337 .fontSize(50) 338 .fontWeight(FontWeight.Bold) 339 .onClick(() => { 340 this.info1.myId += 1; 341 }) 342 Divider() 343 .color(Color.Blue) 344 Text(`info2 id: ${this.info2.myId}`) 345 .fontSize(50) 346 .fontWeight(FontWeight.Bold) 347 .onClick(() => { 348 this.info2.myId += 1; 349 }) 350 Divider() 351 .color(Color.Blue) 352 // Classes inherited from @ObservedV2 are decorated by the decorator of V2, but the class properties cannot be observed by the decorator of V2. Therefore, you are not advised to use the @Observed decorated classes in V2. 353 Text(`messageInfo id: ${this.messageInfo.myId}`) 354 .fontSize(50) 355 .fontWeight(FontWeight.Bold) 356 .onClick(() => { 357 this.messageInfo.myId += 1; 358 }) 359 } 360 .height('100%') 361 .width('100%') 362 .margin(5) 363 } 364} 365``` 366 367You are not advised to use \@Observed decorated classes in V2 because \@Observed and \@Track decorated class properties can only be distinguished but not be observed. In-depth data can be observed only when \@Observed and \@ObjectLink are used to split nested data. However, \@ObjectLink cannot be used in custom components of V2. 368 369When migrating code from V1 to V2, you are not advised to use \@Observed decorated classes in \@ComponentV2 because they are not observable. If you have to use the classes, comply with the following rules: 370 371* \@Observed can only decorate class, and \@Trace cannot be used in \@Observed. 372* \@Observed and \@Track decorated classes are not observable and you can use the decorators only to prevent the entire class from being refreshed when a class property is changed. 373* Classes inherited from @Observed are decorated by the decorator of V2, but the class properties cannot be observed the intra-component decorator of V2. Therefore, class property changes cannot be observed using \@Observed. 374* In the example, the code can be executed properly after you remove the decorator that reports error. Because the observation capability is unavailable, you are not advised to use \@Observed in V2. 375 376### Mixing Use of Custom Components of V1 and V2 When No Variable Is Passed 377 378**1. Use the custom components of V2 in V1.** 379 380```typescript 381@ComponentV2 382struct Child { 383 @Local message: string = "hello"; 384 385 build() { 386 Column() { 387 Text(this.message) 388 .fontSize(50) 389 .fontWeight(FontWeight.Bold) 390 .onClick(() => { 391 this.message = 'world'; 392 }) 393 } 394 } 395} 396 397@Entry 398@Component 399struct Index { 400 @State message: string = 'Hello World'; 401 402 build() { 403 Column() { 404 Text(this.message) 405 .fontSize(50) 406 .fontWeight(FontWeight.Bold) 407 .onClick(() => { 408 this.message = 'world hello'; 409 }) 410 Divider() 411 .color(Color.Blue) 412 Child() 413 } 414 .height('100%') 415 .width('100%') 416 } 417} 418``` 419 420Using the custom components of V2 in V1 performs no impact when no variable is passed. 421 422**2. Use the custom components of V1 in V2.** 423 424```typescript 425@Component 426struct Child { 427 @State message: string = "hello"; 428 429 build() { 430 Column() { 431 Text(this.message) 432 .fontSize(50) 433 .fontWeight(FontWeight.Bold) 434 .onClick(() => { 435 this.message = 'world'; 436 }) 437 } 438 } 439} 440 441@Entry 442@ComponentV2 443struct Index { 444 @Local message: string = 'Hello World'; 445 446 build() { 447 Column() { 448 Text(this.message) 449 .fontSize(50) 450 .fontWeight(FontWeight.Bold) 451 .onClick(() => { 452 this.message = 'world hello'; 453 }) 454 Divider() 455 .color(Color.Blue) 456 Child() 457 } 458 .height('100%') 459 .width('100%') 460 } 461} 462``` 463 464Using the custom components of V1 in V2 performs no impact when no variable is passed. 465 466### Mixing Use of Custom Components of V1 and V2 When Variables Are Passed 467 468**1. V1 > V2: Pass the common variables of V1 to the custom component of V2.** 469 470```typescript 471class Info { 472 myId: number; 473 name: string; 474 475 constructor(myId?: number, name?: string) { 476 this.myId = myId || 0; 477 this.name = name || 'aaa'; 478 } 479} 480 481@ComponentV2 482struct Child { 483 // V2 strictly manages data input. When receiving data from the parent component, the @Param decorator must be used to receive data. 484 @Param @Once message: string = "hello"; // Changes are observable and can be synchronized to the parent component through @Event. @Once can be used to change @Param decorated variables. 485 @Param @Once undefineVal: string | undefined = undefined; // @Once can be used to change @Param decorated variables. 486 @Param info: Info = new Info(); // The class property changes are not observable. 487 @Require @Param set: Set<number>; 488 489 build() { 490 Column() { 491 Text(`child message:${this.message}`) // Display the string. 492 .fontSize(30) 493 .fontWeight(FontWeight.Bold) 494 .onClick(() => { 495 this.message = 'world'; 496 }) 497 498 Divider() 499 .color(Color.Blue) 500 Text ('undefineVal:${this.undefineVal}') // Display undefineVal. 501 .fontSize(30) 502 .fontWeight(FontWeight.Bold) 503 .onClick(() => { 504 this.undefineVal = "change to define"; 505 }) 506 Divider() 507 .color(Color.Blue) 508 Text ('info id:${this.info.myId}') // Display info:myId. 509 .fontSize(30) 510 .fontWeight(FontWeight.Bold) 511 .onClick(() => { 512 this.info.myId++; 513 }) 514 Divider() 515 .color(Color.Blue) 516 ForEach(Array.from(this.set.values()), (item: number) => { // Display set. 517 Text(`${item}`) 518 .fontSize(30) 519 }) 520 } 521 .margin(5) 522 } 523} 524 525@Entry 526@Component 527struct Index { 528 message: string = 'Hello World'; // Simple type. 529 undefineVal: undefined = undefined; // Simple type: undefined. 530 info: Info = new Info(); // Class type. 531 set: Set<number> = new Set([10, 20]); // Built-in type. 532 533 build() { 534 Column() { 535 Text(`message:${this.message}`) 536 .fontSize(30) 537 .fontWeight(FontWeight.Bold) 538 .onClick(() => { 539 this.message = 'world hello'; 540 }) 541 Divider() 542 .color(Color.Blue) 543 Child({ 544 message: this.message, 545 undefineVal: this.undefineVal, 546 info: this.info, 547 set: this.set 548 }) 549 } 550 .height('100%') 551 .width('100%') 552 } 553} 554``` 555 556When the common variables of V1 are passed to a custom component of V2, constraints are as follows: 557 558* The custom component of V2 must receive data through \@Param. 559* To observe the received data changes, use \@Param; to observe the received class changes, use \@ObservedV2 and \@Trace. 560 561**2. V1 > V2: Pass the state variables of V1 to the custom component of V2.** 562 563```typescript 564class Info { 565 myId: number; 566 name: string; 567 568 constructor(myId?: number, name?: string) { 569 this.myId = myId || 0; 570 this.name = name || 'aaa'; 571 } 572} 573 574@ComponentV2 575struct Child { 576 // V2 strictly manages data input. When receiving data from the parent component, the @Param decorator must be used to receive data. 577 @Param @Once message: string = "hello"; 578 @Param @Once undefineVal: string | undefined = undefined; // @Once can be used to change @Param decorated variables. 579 @Param info: Info = new Info(); 580 @Require @Param set: Set<number>; 581 build() { 582 Column() { 583 Text(`child message:${this.message}`) // Display the string. 584 .fontSize(30) 585 .fontWeight(FontWeight.Bold) 586 .onClick(() => { 587 this.message = 'world'; 588 }) 589 Divider() 590 .color(Color.Blue) 591 Text ('undefineVal:${this.undefineVal}') // Display undefineVal. 592 .fontSize(30) 593 .fontWeight(FontWeight.Bold) 594 .onClick(() => { 595 this.undefineVal = "change to define"; 596 }) 597 Divider() 598 .color(Color.Blue) 599 Text ('info id:${this.info.myId}') // Display info:myId. 600 .fontSize(30) 601 .fontWeight(FontWeight.Bold) 602 .onClick(() => { 603 this.info.myId++; 604 }) 605 Divider() 606 .color(Color.Blue) 607 ForEach(Array.from(this.set.values()), (item: number) => { // Display set. 608 Text(`${item}`) 609 .fontSize(30) 610 }) 611 } 612 .margin(5) 613 } 614} 615 616@Entry 617@Component 618struct Index { 619 @State message: string = 'Hello World'; // Simple type data can be passed. 620 @State undefineVal: undefined = undefined; // Simple type data, undefined, can be passed. 621 @State info: Info = new Info(); // Class type cannot be passed. Otherwise, an error is reported during compilation. Remove @State to eliminate the error. 622 @State set: Set<number> = new Set([10, 20]); // Built-in type cannot be passed. Otherwise, an error is reported during compilation. Remove @State to eliminate the error. 623 624 build() { 625 Column() { 626 Text(`message:${this.message}`) 627 .fontSize(30) 628 .fontWeight(FontWeight.Bold) 629 .onClick(() => { 630 this.message = 'world hello'; 631 }) 632 Divider() 633 .color(Color.Blue) 634 Child({ 635 message: this.message, 636 undefineVal: this.undefineVal, 637 info: this.info, 638 set: this.set 639 }) 640 } 641 .height('100%') 642 .width('100%') 643 } 644} 645``` 646 647When the state variable of V1 is assigned to the custom component of V2, rules are as follows: 648 649* Only simple variables are supported. For other types of data, an error is reported during compilation. 650 651* In the example, the \@State decorator is used. Other decorators such as \@Prop, \@Link, \@ObjectLink, \@Provide, \@Consume, \@StorageProp, \@StorageLink, \@LocalStorageProp and \@LocalStorageLink work in the same way as \@State. 652 653**3. V2 > V1: Pass the common variables of V2 to the custom component of V1.** 654 655```typescript 656class Info { 657 myId: number; 658 name: string; 659 660 constructor(myId?: number, name?: string) { 661 this.myId = myId || 0; 662 this.name = name || 'aaa'; 663 } 664} 665 666@Component 667struct Child { 668 // State variable received by V1 from V2. Only @State, @Prop, and @Provide decorators can be used. 669 @State message: string = "hello"; // Changes are observable. 670 @State info: Info = new Info(); // Top-level class property changes are observable. 671 @Prop undefineVal: undefined | string = undefined; 672 @Provide setMap: Set<number> = new Set(); 673 build() { 674 Column() { 675 Text(`child message:${this.message}`) // Display the string. 676 .fontSize(30) 677 .fontWeight(FontWeight.Bold) 678 .onClick(() => { 679 this.message = 'world'; 680 }) 681 Divider() 682 .color(Color.Blue) 683 Text(`undefineVal:${this.undefineVal}`) // Display undefineVal. 684 .fontSize(30) 685 .fontWeight(FontWeight.Bold) 686 .onClick(() => { 687 this.undefineVal = "change to define"; 688 }) 689 Divider() 690 .color(Color.Blue) 691 Text(`info id:${this.info.myId}`) // Display info:myId. 692 .fontSize(30) 693 .fontWeight(FontWeight.Bold) 694 .onClick(() => { 695 this.info.myId++; 696 }) 697 Divider() 698 .color(Color.Blue) 699 ForEach(Array.from(this.setMap.values()), (item: number) => { // Display set. 700 Text(`${item}`) 701 .fontSize(30) 702 }) 703 } 704 .margin(5) 705 } 706} 707 708@Entry 709@ComponentV2 710struct Index { 711 message: string = 'Hello World'; // Simple type. 712 undefineVal: undefined = undefined; // Simple type: undefined. 713 info: Info = new Info(); // Class type. 714 set: Set<number> = new Set([10, 20]); // Built-in type. 715 716 build() { 717 Column() { 718 Text(`message:${this.message}`) 719 .fontSize(30) 720 .fontWeight(FontWeight.Bold) 721 .onClick(() => { 722 this.message = 'world hello'; 723 }) 724 Divider() 725 .color(Color.Blue) 726 Child({ 727 message: this.message, 728 undefineVal: this.undefineVal, 729 info: this.info, 730 setMap: this.set 731 }) 732 } 733 .height('100%') 734 .width('100%') 735 } 736} 737``` 738 739When a common variable of V2 is passed to a custom component of V1: 740 741* V1 can receive data without using the decorator. The received variables are also common variables in the custom component of V1. 742 743* If V1 uses a decorator to receive data, data can be received only through \@State, \@Prop, and \@Provide. 744 745**4. V2 > V1: Pass the state variables of V2 to the custom component of V1.** 746 747```typescript 748class Info { 749 myId: number; 750 name: string; 751 752 constructor(myId?: number, name?: string) { 753 this.myId = myId || 0; 754 this.name = name || 'aaa'; 755 } 756} 757 758@Component 759struct Child { 760 // State variable received by V1 from V2. Only @State, @Prop, and @Provide can be used. 761 @State message: string = "hello"; // Changes are observable. 762 @State info: Info = new Info(); // Top-level class property changes are observable. 763 @Prop undefineVal: undefined | string = undefined; 764 @Provide set: Set<number> = new Set(); 765 build() { 766 Column() { 767 Text(`child message:${this.message}`) // Display the string. 768 .fontSize(30) 769 .fontWeight(FontWeight.Bold) 770 .onClick(() => { 771 this.message = 'world'; 772 }) 773 Divider() 774 .color(Color.Blue) 775 Text(`undefineVal:${this.undefineVal}`) // Display undefineVal. 776 .fontSize(30) 777 .fontWeight(FontWeight.Bold) 778 .onClick(() => { 779 this.undefineVal = "change to define"; 780 }) 781 Divider() 782 .color(Color.Blue) 783 Text(`info id:${this.info.myId}`) // Display info:myId. 784 .fontSize(30) 785 .fontWeight(FontWeight.Bold) 786 .onClick(() => { 787 this.info.myId++; 788 }) 789 790 Divider() 791 .color(Color.Blue) 792 ForEach(Array.from(this.set.values()), (item: number) => { // Display set. 793 Text(`${item}`) 794 .fontSize(30) 795 }) 796 } 797 .margin(5) 798 } 799} 800 801@Entry 802@ComponentV2 803struct Index { 804 @Local message: string = 'Hello World'; // Simple type data can be passed. 805 @Provider() undefineVal: undefined = undefined; // Simple type data, undefined, can be passed. 806 @Consumer() info: Info = new Info(); // Class type can be passed. 807 @Param set: Set<number> = new Set([10, 20]); // Built-in type cannot be passed. Otherwise, an error is reported during compilation. Remove @Param to eliminate the error. 808 809 build() { 810 Column() { 811 Text(`message:${this.message}`) 812 .fontSize(30) 813 .fontWeight(FontWeight.Bold) 814 .onClick(() => { 815 this.message = 'world hello'; 816 }) 817 818 Divider() 819 .color(Color.Blue) 820 Child({ 821 message: this.message, 822 undefineVal: this.undefineVal, 823 info: this.info, 824 set: this.set 825 }) 826 } 827 .height('100%') 828 .width('100%') 829 } 830} 831``` 832 833When the state variables of V2 are passed to a custom component of V1, constraints are as follows: 834 835* V1 can receive data without using the decorator. The received variables are also common variables in the custom component of V1. 836 837* If V1 uses a decorator to receive data, data can be received only through \@State, \@Prop, and \@Provide. 838* If a decorator is used to receive data in V1, data of the built-in type cannot be received. 839 840### Summary 841 842According to the detailed analysis of the mixed use of V1 and V2, when the code of V1 is used in V2, that is, components or classes of V1 are passed to V2, most capabilities of V1 are disabled in V2. When the code of V2 is used in V1, that is, components or classes of V2 are passed to V1, some functions are available, for example, \@ObservedV2 and \@Trace. This is also the most helpful way to observe the V1 nested class data. Therefore, during code development, you are not advised to use V1 and V2 together for mixed development. However, you can gradually migrate the code of V1 to V2 to steadily replace the function code of V1. In addition, you are not advised to use the code of V1 in V2. 843 844## Supplementary Scenarios 845 846Classes can be nested at multiple levels because they are decorated by \@Observed and \@ObservedV2, leading to a complex scenario. This section mainly describes the self-nesting of the class type and the nesting of the built-in type. Lack of in-depth observation capability like \@ObservedV2 and @Trace, the in-depth nesting of \@Observed is not discussed. Only the use scenarios of \@ObservedV2 in V1 are discussed. 847 848### Using \@Observed and \@ObjectLink to Observe Nested Classes 849 850```typescript 851@Observed 852class Info { 853 myId: number; 854 name: string; 855 856 constructor(myId?: number, name?: string) { 857 this.myId = myId || 0; 858 this.name = name || 'aaa'; 859 } 860} 861 862@Observed 863class MessageInfo { // One-level nesting. 864 @Track info: Info; // Prevent the info from being updated when the messageId is changed. 865 @Track messageId: number; // Prevent the info from being updated when the messageId is changed. 866 867 constructor(info?: Info, messageId?: number) { 868 this.info = info || new Info(); 869 this.messageId = messageId || 0; 870 } 871} 872 873@Observed 874class MessageInfoNested { // Dual-level nesting. 875 messageInfo: MessageInfo; 876 877 constructor(messageInfo?: MessageInfo) { 878 this.messageInfo = messageInfo || new MessageInfo(); 879 } 880} 881 882@Component 883struct GrandSon { 884 @ObjectLink info: Info; 885 886 build() { 887 Column() { 888 Text ('ObjectLink info info.myId:${this.info.myId}') // After @ObjectLink disassembles the level twice, the change is observable. 889 .fontSize(30) 890 .onClick(() => { 891 this.info.myId++; 892 }) 893 } 894 } 895} 896 897@Component 898struct Child { 899 @ObjectLink messageInfo: MessageInfo; 900 901 build() { 902 Column() { 903 Text(`ObjectLink MessageInfo messageId:${this.messageInfo.messageId}`) // After @ObjectLink disassembles the levels, the change of the top-level class property is observable. 904 .fontSize(30) 905 .onClick(() => { 906 this.messageInfo.messageId++; 907 }) 908 Divider() 909 .color(Color.Blue) 910 Text(`ObjectLink MessageInfo info.myId:${this.messageInfo.info.myId}`) // After @ObjectLink disassembles the level, the change is not observable. 911 .fontSize(30) 912 .onClick(() => { 913 this.messageInfo.info.myId++; 914 }) 915 GrandSon({info: this.messageInfo.info}); // Continue to disassemble the top-level child components. 916 } 917 } 918} 919 920 921 922@Entry 923@Component 924struct Index { 925 @State messageInfoNested: MessageInfoNested = new MessageInfoNested(); // For the data nested at three levels, you need to observe all data. 926 927 build() { 928 Column() { 929 // Observe messageInfoNested. 930 Text(`messageInfoNested messageId:${this.messageInfoNested.messageInfo.messageId}`) // @State can only observe the top-level class properties but not their changes. 931 .fontSize(30) 932 .onClick(() => { 933 this.messageInfoNested.messageInfo.messageId++; 934 }) 935 Divider() 936 .color(Color.Blue) 937 // Observe messageInfoId through @ObjectLink. 938 Child({messageInfo: this.messageInfoNested.messageInfo}) // After disassembling, you can use @ObjectLink to observe the lower-level changes. 939 Divider() 940 .color(Color.Blue) 941 } 942 .height('100%') 943 .width('100%') 944 .margin(10) 945 } 946} 947``` 948 949The sample code uses a three-layer nesting to show: 950 951* The observation capability of the decorator of V1 is to function as a proxy for data. Therefore, when data is nested, the decorator of V1 can only disassemble the child component to observe lower-level data through \@Observed and \@ObjectLink. 952* \@Track is used to prevent the **info** in the **MessageInfo** class from being updated when the **messageId** is changed. You can remove \@Track to observe the change. When the **messageId** is changed, the **info** is also changed. However, this change cannot be observed by \@ObjectLink. 953 954### Using @ObsevedV2 and @Trace to Observe Nested Classes 955 956```typescript 957@ObservedV2 958class Info { 959 @Trace myId: number; 960 name: string; 961 962 constructor(myId?: number, name?: string) { 963 this.myId = myId || 0; 964 this.name = name || 'aaa'; 965 } 966} 967 968@Observed 969class MessageInfo { // One-level nesting. 970 @Track info: Info; // Prevent the info from being updated when the messageId is changed. 971 @Track messageId: number; // Prevent the info from being updated when the messageId is changed. 972 973 constructor(info?: Info, messageId?: number) { 974 this.info = info || new Info(); // Use the input info or create an Info. 975 this.messageId = messageId || 0; 976 } 977} 978 979@Observed 980class MessageInfoNested { // Dual-level nesting. If MessageInfoNested is decorated by @ObservedV2, it cannot be decorated by the state variable decorator of V1, such as @State. 981 messageInfo: MessageInfo; 982 983 constructor(messageInfo?: MessageInfo) { 984 this.messageInfo = messageInfo || new MessageInfo(); 985 } 986} 987 988@Component 989struct Child { 990 @ObjectLink messageInfo: MessageInfo; 991 992 build() { 993 Column() { 994 Text(`ObjectLink MessageInfo messageId:${this.messageInfo.messageId}`) // After @ObjectLink disassembles the levels, the change of the top-level class property is observable. 995 .fontSize(30) 996 .onClick(() => { 997 this.messageInfo.messageId++; 998 }) 999 } 1000 } 1001} 1002 1003@Entry 1004@Component 1005struct Index { 1006 @State messageInfoNested: MessageInfoNested = new MessageInfoNested(); // For the data nested at three levels, you need to observe the internal data. 1007 1008 build() { 1009 Column() { 1010 // Observe messageInfoNested. @State can only observe the top-level data and cannot observe the changes. 1011 Text(`messageInfoNested messageId:${this.messageInfoNested.messageInfo.messageId}`) 1012 .fontSize(30) 1013 .onClick(() => { 1014 this.messageInfoNested.messageInfo.messageId++; 1015 }) 1016 Divider() 1017 .color(Color.Blue) 1018 Text(`messageInfoNested name:${this.messageInfoNested.messageInfo.info.name}`) // Being not decorated by @Trace, it is not observable. 1019 .fontSize(30) 1020 .onClick(() => { 1021 this.messageInfoNested.messageInfo.info.name += 'a'; 1022 }) 1023 Divider() 1024 .color(Color.Blue) 1025 Text(`messageInfoNested myId:${this.messageInfoNested.messageInfo.info.myId}`) // Decorated by @Trace, data changes can be observed no matter how many levels data is nested in. 1026 .fontSize(30) 1027 .onClick(() => { 1028 this.messageInfoNested.messageInfo.info.myId++; 1029 }) 1030 Divider() 1031 .color(Color.Blue) 1032 // Observe messageInfoId through @ObjectLink. 1033 Child({messageInfo: this.messageInfoNested.messageInfo}) // After disassembling, you can use @ObjectLink to observe the lower-level changes. 1034 } 1035 .height('100%') 1036 .width('100%') 1037 .margin(10) 1038 } 1039} 1040``` 1041 1042The sample code shows: 1043 1044* \@observedV2 and \@Trace nest the observation capability to the class properties. Therefore, when a class property is marked by @Trace, the change can be observed regardless of the number of nested levels. 1045* When \@ObservdV2 and \@Observed are used together, the decorator used by the outermost class determines whether the class object can be decorated by the decorator of V1. For example, the class decorated by \@ObservedV2 in the lower level does not affect the outermost class decorated by the decorator of V1. 1046