• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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