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