1# \@Prop Decorator: One-Way Synchronization from the Parent Component to Child Components
2
3
4One-way synchronization is supported between an \@Prop decorated variable a variable of its parent component. This means that, an \@Prop decorated variable is mutable, and its changes will not be synchronized to the parent component.
5
6
7> **NOTE**
8>
9> This decorator can be used in ArkTS widgets since API version 9.
10>
11> This decorator can be used in atomic services since API version 11.
12
13## Overview
14
15For the \@Prop decorated variable of a child component, the change synchronization to the parent component is uni-directional.
16
17- An \@Prop variable is allowed to be modified locally, but the change does not propagate back to its parent component.
18
19- Whenever the data source changes, the \@Prop decorated variable gets updated, and any locally made changes are overwritten. In other words, the change is synchronized from the parent component to the (owning) child component, but not the other way around.
20
21
22
23## Restrictions
24
25- When decorating variables, \@Prop makes a deep copy, during which all types, except primitive types, Map, Set, Date, and Array, will be lost. For example, for complex types provided by N-API, such as [PixelMap](../reference/apis-image-kit/js-apis-image.md#pixelmap7), because they are partially implemented in the native code, complete data cannot be obtained through a deep copy in ArkTS.
26
27- The \@Prop decorator cannot be used in custom components decorated by \@Entry.
28
29
30## Rules of Use
31
32| \@Prop Decorator| Description                                      |
33| ----------- | ---------------------------------------- |
34| Decorator parameters      | None.                                       |
35| Synchronization type       | One-way: from the data source provided by the parent component to the \@Prop decorated variable. For details about the scenarios of nested types, see [Observed Changes](#observed-changes).|
36| Allowed variable types  | Object, class, string, number, Boolean, enum, and array of these types.<br>**undefined** or **null** (**any** is not supported).<br>Date type.<br>(Applicable to API version 11 or later) Map and Set types.<br>The union types defined by the ArkUI framework, including Length, ResourceStr, and ResourceColor.<br>The type must be specified.<br>The type must be the same as that of the [data source](arkts-state-management-overview.md#basic-concepts). There are three cases:<br/>- Synchronizing the \@Prop decorated variable from a variable decorated by \@State or other decorators. Example: [Simple Type @Prop Synced from @State in Parent Component](#simple-type-prop-synced-from-state-in-parent-component).<br>- Synchronizing the \@Prop decorated variable from the item of an array decorated by an \@State or other decorators. Example: [Simple Type @Prop Synced from @State Array Item in Parent Component](#simple-type-prop-synced-from-state-array-item-in-parent-component).<br>- Synchronizing the \@Prop decorated variable from a state property of the Object or class type in the parent component. Example: [Class Object Type @Prop Synced from @State Class Object Property in Parent Component](#class-object-type-prop-synced-from-state-class-object-property-in-parent-component).<br>For details about the scenarios of supported types, see [Observed Changes](#observed-changes).<br>(Applicable to API version 11 or later) Union type of the preceding types, for example, **string \| number**, **string \| undefined** or **ClassA \| null**. For details, see [Union Type @Prop](#union-type-prop).<br>**NOTE**<br>When **undefined** or **null** is used, you are advised to explicitly specify the type to pass the TypeScript type check. For example, **@Prop a: string \| undefined = undefined** is recommended; **@Prop a: string = undefined** is not recommended. |
37| Number of nested layers       | In component reuse scenarios, it is recommended that @Prop be nested with no more than five layers of data. If @Prop is nested with too many layers of data, garbage collection and increased memory usage caused by deep copy will arise, resulting in performance issues. To avoid such issues, use [\@ObjectLink](arkts-observed-and-objectlink.md) instead.|
38| Initial value for the decorated variable  | Local initialization is allowed. If this decorator is used together with [\@Require](arkts-require.md) in API version 11, the parent component must construct input parameters.|
39
40
41## Variable Transfer/Access Rules
42
43| Transfer/Access    | Description                                      |
44| --------- | ---------------------------------------- |
45| Initialization from the parent component  | Optional if local initialization is used and mandatory otherwise. An @Prop decorated variable can be initialized from a regular variable (whose change does not trigger UI refresh) or an [\@State](arkts-state.md), [\@Link](arkts-link.md), @Prop, [\@Provide](arkts-provide-and-consume.md), [\@Consume](arkts-provide-and-consume.md), [\@ObjectLink](arkts-observed-and-objectlink.md), [\@StorageLink](arkts-appstorage.md#storagelink), [\@StorageProp](arkts-appstorage.md#storageprop), [\@LocalStorageLink](arkts-localstorage.md#localstoragelink), or [\@LocalStorageProp](arkts-localstorage.md#localstorageprop) decorated variable in its parent component.|
46| Child component initialization | \@Prop can be used for initialization of a regular variable or \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component.|
47| Access| Private, accessible only within the component.               |
48
49
50  **Figure 1** Initialization rule 
51
52
53![en-us_image_0000001552972029](figures/en-us_image_0000001552972029.png)
54
55
56## Observed Changes and Behavior
57
58
59### Observed Changes
60
61\@Prop decorated variables can observe the following changes:
62
63- When the decorated variable is of the Object, class, string, number, Boolean, or enum type, its value change can be observed.
64
65  ```ts
66  // Simple type
67  @Prop count: number;
68  // The value change can be observed.
69  this.count = 1;
70  // Complex type
71  @Prop title: Model;
72  // The value change can be observed.
73  this.title = new Model('Hi');
74  ```
75
76- When the decorated variable is of the Object or class type, the value changes of properties at the first layer, that is, the properties that **Object.keys(observedObject)** returns, can be observed.
77
78```
79class ClassA {
80  public value: string;
81  constructor(value: string) {
82    this.value = value;
83  }
84}
85class Model {
86  public value: string;
87  public a: ClassA;
88  constructor(value: string, a: ClassA) {
89    this.value = value;
90    this.a = a;
91  }
92}
93
94@Prop title: Model;
95// The value changes at the first layer can be observed.
96this.title.value = 'Hi'
97// The value changes at the second layer cannot be observed.
98this.title.a.value = 'ArkUi' 
99```
100
101In the scenarios of nested objects, if a class is decorated by \@Observed, the value changes of the class property can be observed. For details, see [@Prop Nesting Scenario](#prop-nesting-scenario).
102
103- When the decorated variable is of the array type, the value change of the array as well as the addition, deletion, and update of array items can be observed.
104
105```
106// Assume that the object decorated by @State is an array.
107@Prop title: string[]
108// The value change of the array itself can be observed.
109this.title = ['1']
110// The value change of array items can be observed.
111this.title[0] = '2'
112// The deletion of array items can be observed.
113this.title.pop()
114// The addition of array items can be observed.
115this.title.push('3')
116```
117
118For synchronization between \@State and \@Prop decorated variables:
119
120- The value of an \@State decorated variable in the parent component is used to initialize an \@Prop decorated variable in the child component. Any change to an \@State decorated variable is updated to the @Prop decorated variable.
121- However, any change to the @Prop decorated variable does not affect the value of its source @State decorated variable.
122- In addition to \@State, the source can also be decorated with \@Link or \@Prop, where the mechanisms for syncing the \@Prop decorated variable is the same.
123- The source and \@Prop decorated variable must be of the same type. The \@Prop decorated variable can be of simple and class types.
124
125- When the decorated variable is of the Date type, the value change of the **Date** object can be observed, and the following APIs can be called to update **Date** properties: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**.
126
127```ts
128@Component
129struct DateComponent {
130  @Prop selectedDate: Date = new Date('');
131
132  build() {
133    Column() {
134      Button('child update the new date')
135        .margin(10)
136        .onClick(() => {
137          this.selectedDate = new Date('2023-09-09')
138        })
139      Button(`child increase the year by 1`).onClick(() => {
140        this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
141      })
142      DatePicker({
143        start: new Date('1970-1-1'),
144        end: new Date('2100-1-1'),
145        selected: this.selectedDate
146      })
147    }
148  }
149}
150
151@Entry
152@Component
153struct ParentComponent {
154  @State parentSelectedDate: Date = new Date('2021-08-08');
155
156  build() {
157    Column() {
158      Button('parent update the new date')
159        .margin(10)
160        .onClick(() => {
161          this.parentSelectedDate = new Date('2023-07-07')
162        })
163      Button('parent increase the day by 1')
164        .margin(10)
165        .onClick(() => {
166          this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1)
167        })
168      DatePicker({
169        start: new Date('1970-1-1'),
170        end: new Date('2100-1-1'),
171        selected: this.parentSelectedDate
172      })
173
174      DateComponent({ selectedDate: this.parentSelectedDate })
175    }
176
177  }
178}
179```
180
181- When the decorated variable is **Map**, value changes of **Map** can be observed. In addition, you can call the **set**, **clear**, and **delete** APIs of **Map** to update its value. For details, see [Decorating Variables of the Map Type](#decorating-variables-of-the-map-type).
182
183- When the decorated variable is **Set**, value changes of **Set** can be observed. In addition, you can call the **add**, **clear**, and **delete** APIs of **Set** to update its value. For details, see [Decorating Variables of the Set Type](#decorating-variables-of-the-set-type).
184
185### Framework Behavior
186
187To understand the value initialization and update mechanism of the \@Prop decorated variable, it is necessary to understand the parent component and the initial render and update process of the child component that owns the \@Prop decorated variable.
188
1891. Initial render:
190   1. The execution of the parent component's **build()** function creates a new instance of the child component, and the parent component provides a source for the @Prop decorated variable.
191   2. The @Prop decorated variable is initialized.
192
1932. Update:
194   1. When the @Prop decorated variable is modified locally, the change does not propagate back to its parent component.
195   2. When the data source of the parent component is updated, the \@Prop decorated variable in the child component is reset, and its local value changes are overwritten.
196
197> **NOTE**
198>
199> The update of an \@Prop decorated variable relies on the re-rendering of the owning custom component. As such, when the application is in the background, the \@Prop decorated variable cannot be updated. In this case, use \@Link instead.
200
201
202## Usage Scenarios
203
204
205### Simple Type Sync from @State of the Parent Component to @Prop of the Child Component
206
207
208In this example, the \@Prop decorated **count** variable in the **CountDownComponent** child component is initialized from the \@State decorated **countDownStartValue** variable in the **ParentComponent**. When **Try again** is touched, the value of the **count** variable is modified, but the change remains within the **CountDownComponent** and does not affect the **ParentComponent**.
209
210
211Updating **countDownStartValue** in the **ParentComponent** will update the value of the @Prop decorated **count**.
212
213
214
215```ts
216@Component
217struct CountDownComponent {
218  @Prop count: number = 0;
219  costOfOneAttempt: number = 1;
220
221  build() {
222    Column() {
223      if (this.count > 0) {
224        Text(`You have ${this.count} Nuggets left`)
225      } else {
226        Text('Game over!')
227      }
228      // Changes to the @Prop decorated variables are not synchronized to the parent component.
229      Button(`Try again`).onClick(() => {
230        this.count -= this.costOfOneAttempt;
231      })
232    }
233  }
234}
235
236@Entry
237@Component
238struct ParentComponent {
239  @State countDownStartValue: number = 10;
240
241  build() {
242    Column() {
243      Text(`Grant ${this.countDownStartValue} nuggets to play.`)
244      // Changes to the data source provided by the parent component are synchronized to the child component.
245      Button(`+1 - Nuggets in New Game`).onClick(() => {
246        this.countDownStartValue += 1;
247      })
248      // Updating the parent component will also update the child component.
249      Button(`-1  - Nuggets in New Game`).onClick(() => {
250        this.countDownStartValue -= 1;
251      })
252
253      CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
254    }
255  }
256}
257```
258
259
260In the preceding example:
261
262
2631. On initial render, when the **CountDownComponent** child component is created, its @Prop decorated **count** variable is initialized from the \@State decorated **countDownStartValue** variable in the **ParentComponent**.
264
2652. When the "+1" or "-1" button is touched, the @State decorated **countDownStartValue** of the **ParentComponent** changes. This will cause the **ParentComponent** to re-render. At the minimum, the **CountDownComponent** will be updated because of the change in the **count** variable value.
266
2673. Because of the change in the **count** variable value, the **CountDownComponent** child component will re-render. At a minimum, the **if** statement's condition (**this.counter> 0**) is evaluated, and the **\<Text>** child component inside the **if** statement would be updated.
268
2694. When **Try again** in the **CountDownComponent** child component is touched, the value of the **count** variable is modified, but the change remains within the child component and does not affect the **countDownStartValue** in the parent component.
270
2715. Updating **countDownStartValue** will overwrite the local value changes of the @Prop decorated **count** in the **CountDownComponent** child component.
272
273
274### Simple Type @Prop Synced from @State Array Item in Parent Component
275
276
277The \@State decorated array an array item in the parent component can be used as data source to initialize and update a @Prop decorated variable. In the following example, the \@State decorated array **arr** in the parent component **Index** initializes the \@Prop decorated **value** variable in the child component **Child**.
278
279```ts
280@Component
281struct Child {
282  @Prop value: number = 0;
283
284  build() {
285    Text(`${this.value}`)
286      .fontSize(50)
287      .onClick(() => {
288        this.value++
289      })
290  }
291}
292
293@Entry
294@Component
295struct Index {
296  @State arr: number[] = [1, 2, 3];
297
298  build() {
299    Row() {
300      Column() {
301        Child({ value: this.arr[0] })
302        Child({ value: this.arr[1] })
303        Child({ value: this.arr[2] })
304
305        Divider().height(5)
306
307        ForEach(this.arr,
308          (item: number) => {
309            Child({ value: item })
310          },
311          (item: number) => item.toString()
312        )
313        Text('replace entire arr')
314          .fontSize(50)
315          .onClick(() => {
316            // Both arrays contain item "3".
317            this.arr = this.arr[0] == 1 ? [3, 4, 5] : [1, 2, 3];
318          })
319      }
320    }
321  }
322}
323```
324
325
326Initial render creates six instances of the **Child** component. Each \@Prop decorated variable is initialized with a copy of an array item. The **onclick** event handler of the **Child** component changes the local variable value.
327
328
329Click **1** six times, 2 five times, and **3** four times on the page. The local values of all variables are then changed to **7**.
330
331```
3327
3337
3347
335----
3367
3377
3387
339```
340
341
342After **replace entire arr** is clicked, the following information is displayed:
343
344```
3453
3464
3475
348----
3497
3504
3515
352```
353
354
355- Changes made in the **Child** component are not synchronized to the parent component **Index**. Therefore, even if the values of the six instances of the **Child** component are **7**, the value of **this.arr** in the **Index** component is still **[1,2,3]**.
356
357- After **replace entire arr** is clicked, if **this.arr[0] == 1** is true, **this.arr** is set to **[3, 4, 5]**.
358
359- Because **this.arr[0]** has been changed, the **Child({value: this.arr[0]})** component synchronizes the update of **this.arr[0]** to the instance's \@Prop decorated variable. The same happens for **Child({value: this.arr[1]})** and **Child({value: this.arr[2]})**.
360
361
362- The change of **this.arr** causes **ForEach** to update: According to the diff algorithm, the array item with the ID **3** is retained in this update, array items with IDs **1** and **2** are deleted, and array items with IDs **4** and **5** are added. The array before and after the update is **[1, 2, 3]** and **[3, 4, 5]**, respectively. This implies that the **Child** instance generated for item **3** is moved to the first place, but not updated. In this case, the component value corresponding to **3** is **7**, and the final render result of **ForEach** is **7**, **4**, and **5**.
363
364
365### Class Object Type @Prop Synced from @State Class Object Property in Parent Component
366
367In a library with one book and two readers, each reader can mark the book as read, and the marking does not affect the other reader. Technically speaking, local changes to the \@Prop decorated **book** object do not sync back to the @State decorated **book** in the **Library** component.
368
369In this example, the \@Observed decorator can be applied to the **book** class, but it is not mandatory. It is only needed for nested structures. This will be further explained in [Class Type @Prop Synced from @State Array Item in Parent Component](#class-type-prop-synced-from-state-array-item-in-parent-component).
370
371
372```ts
373class Book {
374  public title: string;
375  public pages: number;
376  public readIt: boolean = false;
377
378  constructor(title: string, pages: number) {
379    this.title = title;
380    this.pages = pages;
381  }
382}
383
384@Component
385struct ReaderComp {
386  @Prop book: Book = new Book("", 0);
387
388  build() {
389    Row() {
390      Text(this.book.title)
391      Text(`...has${this.book.pages} pages!`)
392      Text(`...${this.book.readIt ? "I have read" : 'I have not read it'}`)
393        .onClick(() => this.book.readIt = true)
394    }
395  }
396}
397
398@Entry
399@Component
400struct Library {
401  @State book: Book = new Book('100 secrets of C++', 765);
402
403  build() {
404    Column() {
405      ReaderComp({ book: this.book })
406      ReaderComp({ book: this.book })
407    }
408  }
409}
410```
411
412### Class Type @Prop Synced from @State Array Item in Parent Component
413
414In the following example, a property of the **Book** object in the \@State decorated **allBooks** array is changed, but the system does not respond when **Mark read for everyone** is clicked. This is because the property is nested at the second layer, and the \@State decorator can observe only properties at the first layer. Therefore, the framework does not update **ReaderComp**.
415
416```ts
417let nextId: number = 1;
418
419// @Observed
420class Book {
421  public id: number;
422  public title: string;
423  public pages: number;
424  public readIt: boolean = false;
425
426  constructor(title: string, pages: number) {
427    this.id = nextId++;
428    this.title = title;
429    this.pages = pages;
430  }
431}
432
433@Component
434struct ReaderComp {
435  @Prop book: Book = new Book("", 1);
436
437  build() {
438    Row() {
439      Text(` ${this.book ? this.book.title : "Book is undefined"}`).fontColor('#e6000000')
440      Text(` has ${this.book ? this.book.pages : "Book is undefined"} pages!`).fontColor('#e6000000')
441      Text(` ${this.book ? this.book.readIt ? "I have read" : 'I have not read it' : "Book is undefined"}`).fontColor('#e6000000')
442        .onClick(() => this.book.readIt = true)
443    }
444  }
445}
446
447@Entry
448@Component
449struct Library {
450  @State allBooks: Book[] = [new Book("C#", 765), new Book("JS", 652), new Book("TS", 765)];
451
452  build() {
453    Column() {
454      Text('library`s all time favorite')
455        .width(312)
456        .height(40)
457        .backgroundColor('#0d000000')
458        .borderRadius(20)
459        .margin(12)
460        .padding({ left: 20 })
461        .fontColor('#e6000000')
462      ReaderComp({ book: this.allBooks[2] })
463        .backgroundColor('#0d000000')
464        .width(312)
465        .height(40)
466        .padding({ left: 20, top: 10 })
467        .borderRadius(20)
468        .colorBlend('#e6000000')
469      Divider()
470      Text('Books on loan to a reader')
471        .width(312)
472        .height(40)
473        .backgroundColor('#0d000000')
474        .borderRadius(20)
475        .margin(12)
476        .padding({ left: 20 })
477        .fontColor('#e6000000')
478      ForEach(this.allBooks, (book: Book) => {
479        ReaderComp({ book: book })
480          .margin(12)
481          .width(312)
482          .height(40)
483          .padding({ left: 20, top: 10 })
484          .backgroundColor('#0d000000')
485          .borderRadius(20)
486      },
487        (book: Book) => book.id.toString())
488      Button('Add new')
489        .width(312)
490        .height(40)
491        .margin(12)
492        .fontColor('#FFFFFF 90%')
493        .onClick(() => {
494          this.allBooks.push(new Book("JA", 512));
495        })
496      Button('Remove first book')
497        .width(312)
498        .height(40)
499        .margin(12)
500        .fontColor('#FFFFFF 90%')
501        .onClick(() => {
502          if (this.allBooks.length > 0){
503            this.allBooks.shift();
504          } else {
505            console.log("length <= 0")
506          }
507        })
508      Button("Mark read for everyone")
509        .width(312)
510        .height(40)
511        .margin(12)
512        .fontColor('#FFFFFF 90%')
513        .onClick(() => {
514          this.allBooks.forEach((book) => book.readIt = true)
515        })
516    }
517  }
518}
519```
520
521 To observe the property of the **Book** object, you must use \@Observed to decorate the **Book** class. Note that the \@Prop decorated state variable in the child component is synchronized from the data source of the parent component in uni-directional manner. This means that, the changes of the \@Prop decorated **book** in **ReaderComp** are not synchronized to the parent **library** component. The parent component triggers UI re-rendering only when the value is updated (compared with the last state).
522
523```ts
524@Observed
525class Book {
526  public id: number;
527  public title: string;
528  public pages: number;
529  public readIt: boolean = false;
530
531  constructor(title: string, pages: number) {
532    this.id = nextId++;
533    this.title = title;
534    this.pages = pages;
535  }
536}
537```
538
539All instances of the \@Observed decorated class are wrapped with an opaque proxy object. This proxy can detect all property changes inside the wrapped object. If any property change happens, the proxy notifies the \@Prop, and the \@Prop value will be updated.
540
541![Video-prop-UsageScenario-one](figures/Video-prop-UsageScenario-one.gif)
542
543### Simple Type @Prop with Local Initialization and No Sync from Parent Component
544
545To enable an \@Component decorated component to be reusable, \@Prop allows for optional local initialization. This makes the synchronization with a variable in the parent component a choice, rather than mandatory. Providing a data source in the parent component is optional only when local initialization is provided for the \@Prop decorated variable.
546
547The following example includes two @Prop decorated variables in the child component.
548
549- The @Prop decorated variable **customCounter** has no local initialization, and therefore it requires a synchronization source in its parent component. When the source value changes, the @Prop decorated variable is updated.
550
551- The @Prop decorated variable **customCounter2** has local initialization. In this case, specifying a synchronization source in the parent component is allowed but not mandatory.
552
553
554```ts
555@Component
556struct MyComponent {
557  @Prop customCounter: number;
558  @Prop customCounter2: number = 5;
559
560  build() {
561    Column() {
562      Row() {
563        Text(`From Main: ${this.customCounter}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
564      }
565
566      Row() {
567        Button('Click to change locally !')
568          .width(288)
569          .height(40)
570          .margin({ left: 30, top: 12 })
571          .fontColor('#FFFFFF, 90%')
572          .onClick(() => {
573            this.customCounter2++
574          })
575      }
576
577      Row() {
578        Text(`Custom Local: ${this.customCounter2}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
579      }
580    }
581  }
582}
583
584@Entry
585@Component
586struct MainProgram {
587  @State mainCounter: number = 10;
588
589  build() {
590    Column() {
591      Row() {
592        Column() {
593          // customCounter must be initialized from the parent component due to lack of local initialization. Here, customCounter2 does not need to be initialized.
594          MyComponent({ customCounter: this.mainCounter })
595          // customCounter2 of the child component can also be initialized from the parent component. The value from the parent component overwrites the locally assigned value of customCounter2 during initialization.
596          MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
597        }
598      }
599
600      Row() {
601        Column() {
602          Button('Click to change number')
603            .width(288)
604            .height(40)
605            .margin({ left: 30, top: 12 })
606            .fontColor('#FFFFFF, 90%')
607            .onClick(() => {
608              this.mainCounter++
609            })
610        }
611      }
612    }
613  }
614}
615```
616
617![Video-prop-UsageScenario-two](figures/Video-prop-UsageScenario-two.gif)
618
619### \@Prop Nesting Scenario
620
621In nesting scenario, each layer must be decorated with @Observed, and each layer must be received by @Prop. In this way, changes can be observed.
622
623```ts
624// The following is the data structure of a nested class object.
625@Observed
626class ClassA {
627  public title: string;
628
629  constructor(title: string) {
630    this.title = title;
631  }
632}
633
634@Observed
635class ClassB {
636  public name: string;
637  public a: ClassA;
638
639  constructor(name: string, a: ClassA) {
640    this.name = name;
641    this.a = a;
642  }
643}
644```
645
646The following component hierarchy presents a data structure of nested @Prop.
647
648```ts
649@Entry
650@Component
651struct Parent {
652  @State votes: ClassB = new ClassB('Hello', new ClassA('world'))
653
654  build() {
655    Column() {
656      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
657        Button('change ClassB name')
658          .width(312)
659          .height(40)
660          .margin(12)
661          .fontColor('#FFFFFF, 90%')
662          .onClick(() => {
663            this.votes.name = "aaaaa"
664          })
665        Button('change ClassA title')
666          .width(312)
667          .height(40)
668          .margin(12)
669          .fontColor('#FFFFFF, 90%')
670          .onClick(() => {
671            this.votes.a.title = "wwwww"
672          })
673        Text(this.votes.name)
674          .fontSize(16)
675          .margin(12)
676          .width(312)
677          .height(40)
678          .backgroundColor('#ededed')
679          .borderRadius(20)
680          .textAlign(TextAlign.Center)
681          .fontColor('#e6000000')
682          .onClick(() => {
683            this.votes.name = 'Bye'
684          })
685        Text(this.votes.a.title)
686          .fontSize(16)
687          .margin(12)
688          .width(312)
689          .height(40)
690          .backgroundColor('#ededed')
691          .borderRadius(20)
692          .textAlign(TextAlign.Center)
693          .onClick(() => {
694            this.votes.a.title = "openHarmony"
695          })
696        Child1({ vote1: this.votes.a })
697      }
698
699    }
700
701  }
702}
703
704
705@Component
706struct Child1 {
707  @Prop vote1: ClassA = new ClassA('');
708
709  build() {
710    Column() {
711      Text(this.vote1.title)
712        .fontSize(16)
713        .margin(12)
714        .width(312)
715        .height(40)
716        .backgroundColor('#ededed')
717        .borderRadius(20)
718        .textAlign(TextAlign.Center)
719        .onClick(() => {
720          this.vote1.title = 'Bye Bye'
721        })
722    }
723  }
724}
725```
726
727![Video-prop-UsageScenario-three](figures/Video-prop-UsageScenario-three.gif)
728
729### Decorating Variables of the Map Type
730
731> **NOTE**
732>
733> Since API version 11, \@Prop supports the Map type.
734
735In this example, the **value** variable is of the Map<number, string> type. When the button is clicked, the value of **message** changes, and the UI is re-rendered.
736
737```ts
738@Component
739struct Child {
740  @Prop value: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
741
742  build() {
743    Column() {
744      ForEach(Array.from(this.value.entries()), (item: [number, string]) => {
745        Text(`${item[0]}`).fontSize(30)
746        Text(`${item[1]}`).fontSize(30)
747        Divider()
748      })
749      Button('child init map').onClick(() => {
750        this.value = new Map([[0, "a"], [1, "b"], [3, "c"]])
751      })
752      Button('child set new one').onClick(() => {
753        this.value.set(4, "d")
754      })
755      Button('child clear').onClick(() => {
756        this.value.clear()
757      })
758      Button('child replace the first one').onClick(() => {
759        this.value.set(0, "aa")
760      })
761      Button('child delete the first one').onClick(() => {
762        this.value.delete(0)
763      })
764    }
765  }
766}
767
768
769@Entry
770@Component
771struct MapSample2 {
772  @State message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
773
774  build() {
775    Row() {
776      Column() {
777        Child({ value: this.message })
778      }
779      .width('100%')
780    }
781    .height('100%')
782  }
783}
784```
785
786### Decorating Variables of the Set Type
787
788> **NOTE**
789>
790> Since API version 11, \@Prop supports the Set type.
791
792In this example, the **message** variable is of the Set\<number\> type. When the button is clicked, the value of **message** changes, and the UI is re-rendered.
793
794```ts
795@Component
796struct Child {
797  @Prop message: Set<number> = new Set([0, 1, 2, 3, 4])
798
799  build() {
800    Column() {
801      ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
802        Text(`${item[0]}`).fontSize(30)
803        Divider()
804      })
805      Button('init set').onClick(() => {
806        this.message = new Set([0, 1, 2, 3, 4])
807      })
808      Button('set new one').onClick(() => {
809        this.message.add(5)
810      })
811      Button('clear').onClick(() => {
812        this.message.clear()
813      })
814      Button('delete the first one').onClick(() => {
815        this.message.delete(0)
816      })
817    }
818    .width('100%')
819  }
820}
821
822
823@Entry
824@Component
825struct SetSample11 {
826  @State message: Set<number> = new Set([0, 1, 2, 3, 4])
827
828  build() {
829    Row() {
830      Column() {
831        Child({ message: this.message })
832      }
833      .width('100%')
834    }
835    .height('100%')
836  }
837}
838```
839
840## Union Type @Prop 
841
842@Prop supports **undefined**, **null**, and union types. In the following example, the type of **animal** is Animals | undefined. If the property or type of **animal** is changed when the button in the parent component **Zoo** is clicked, the change will be synced to the child component.
843
844```ts
845class Animals {
846  public name: string;
847
848  constructor(name: string) {
849    this.name = name;
850  }
851}
852
853@Component
854struct Child {
855  @Prop animal: Animals | undefined;
856
857  build() {
858    Column() {
859      Text(`Child's animal is  ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
860
861      Button('Child change animals into tigers')
862        .onClick(() => {
863          // Assign the value of an instance of Animals.
864          this.animal = new Animals("Tiger")
865        })
866
867      Button('Child change animal to undefined')
868        .onClick(() => {
869          // Assign the value undefined.
870          this.animal = undefined
871        })
872
873    }.width('100%')
874  }
875}
876
877@Entry
878@Component
879struct Zoo {
880  @State animal: Animals | undefined = new Animals("lion");
881
882  build() {
883    Column() {
884      Text(`Parents' animals are  ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
885
886      Child({animal: this.animal})
887
888      Button('Parents change animals into dogs')
889        .onClick(() => {
890          // Determine the animal type and update the property.
891          if (this.animal instanceof Animals) {
892            this.animal.name = "Dog"
893          } else {
894            console.info('num is undefined, cannot change property')
895          }
896        })
897
898      Button('Parents change animal to undefined')
899        .onClick(() => {
900          // Assign the value undefined.
901          this.animal = undefined
902        })
903    }
904  }
905}
906```
907
908
909## FAQs
910
911### \@Prop Decorated State Variable Not Initialized
912
913The \@Prop decorated state variable must be initialized. If not initialized locally, the variable must be initialized from the parent component. If it has been initialized locally, initialization from the parent component is optional.
914
915[Incorrect Example]
916
917```ts
918@Observed
919class Commodity {
920  public price: number = 0;
921
922  constructor(price: number) {
923    this.price = price;
924  }
925}
926
927@Component
928struct PropChild {
929  @Prop fruit: Commodity; // The state variable is not initialized locally.
930
931  build() {
932    Text(`PropChild fruit ${this.fruit.price}`)
933      .onClick(() => {
934        this.fruit.price += 1;
935      })
936  }
937}
938
939@Entry
940@Component
941struct Parent {
942  @State fruit: Commodity[] = [new Commodity(1)];
943
944  build() {
945    Column() {
946      Text(`Parent fruit ${this.fruit[0].price}`)
947        .onClick(() => {
948          this.fruit[0].price += 1;
949        })
950
951      // The @Prop state variable is not initialized locally, nor initialized from the parent component.
952      PropChild()
953    }
954  }
955}
956```
957
958[Correct Example]
959
960```ts
961@Observed
962class Commodity {
963  public price: number = 0;
964
965  constructor(price: number) {
966    this.price = price;
967  }
968}
969
970@Component
971struct PropChild1 {
972  @Prop fruit: Commodity; // The state variable is not initialized locally.
973
974  build() {
975    Text(`PropChild1 fruit ${this.fruit.price}`)
976      .onClick(() => {
977        this.fruit.price += 1;
978      })
979  }
980}
981
982@Component
983struct PropChild2 {
984  @Prop fruit: Commodity = new Commodity(1); // The state variable is initialized locally.
985
986  build() {
987    Text(`PropChild2 fruit ${this.fruit.price}`)
988      .onClick(() => {
989        this.fruit.price += 1;
990      })
991  }
992}
993
994@Entry
995@Component
996struct Parent {
997  @State fruit: Commodity[] = [new Commodity(1)];
998
999  build() {
1000    Column() {
1001      Text(`Parent fruit ${this.fruit[0].price}`)
1002        .onClick(() => {
1003          this.fruit[0].price += 1;
1004        })
1005
1006      // @PropChild1 is not initialized locally and must be initialized from the parent component.
1007      PropChild1({ fruit: this.fruit[0] })
1008      // @PropChild2 is initialized locally. In this case, initialization from the parent component is optional.
1009      PropChild2()
1010      PropChild2({ fruit: this.fruit[0] })
1011    }
1012  }
1013}
1014```
1015