1e41f4b71Sopenharmony_ci# LocalStorage: Storing UI State
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci
4e41f4b71Sopenharmony_ciLocalStorage provides storage for the page-level UI state. The parameters of the LocalStorage type accepted through the \@Entry decorator share the same LocalStorage instance on the page. LocalStorage also allows for state sharing between pages with UIAbility instances.
5e41f4b71Sopenharmony_ci
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciThis topic describes only the LocalStorage application scenarios and related decorators: \@LocalStorageProp and \@LocalStorageLink.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci
10e41f4b71Sopenharmony_ci> **NOTE**
11e41f4b71Sopenharmony_ci>
12e41f4b71Sopenharmony_ci> LocalStorage is supported since API version 9.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci
15e41f4b71Sopenharmony_ci## Overview
16e41f4b71Sopenharmony_ci
17e41f4b71Sopenharmony_ciLocalStorage is an in-memory "database" that ArkTS provides for storing state variables required to build pages of the application UI.
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci- An application can create multiple LocalStorage instances. These instances can be shared on a page or, by using the **GetShared** API, across pages in a UIAbility instance.
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ci- The root node of a component tree, that is, the \@Component decorated by \@Entry, can be assigned to a LocalStorage instance. All child instances of this custom component automatically gain access to the same LocalStorage instance.
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci- An \@Component decorated component has access to at most one LocalStorage instance and to [AppStorage](arkts-appstorage.md). A component not decorated with \@Entry cannot be assigned a LocalStorage instance. It can only accept a LocalStorage instance passed from its parent component through \@Entry. A LocalStorage instance can be assigned to multiple components in the component tree.
24e41f4b71Sopenharmony_ci
25e41f4b71Sopenharmony_ci- All attributes in LocalStorage are mutable.
26e41f4b71Sopenharmony_ci
27e41f4b71Sopenharmony_ciThe application determines the lifecycle of a LocalStorage object. The JS Engine will garbage collect a LocalStorage object when the application releases the last reference to it, which includes deleting the last custom component.
28e41f4b71Sopenharmony_ci
29e41f4b71Sopenharmony_ciLocalStorage provides two decorators based on the synchronization type of the component decorated with \@Component:
30e41f4b71Sopenharmony_ci
31e41f4b71Sopenharmony_ci- [@LocalStorageProp](#localstorageprop): creates a one-way data synchronization with the named attribute in LocalStorage.
32e41f4b71Sopenharmony_ci
33e41f4b71Sopenharmony_ci- [@LocalStorageLink](#localstoragelink): creates a two-way data synchronization with the named attribute in LocalStorage.
34e41f4b71Sopenharmony_ci
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ci## Constraints
37e41f4b71Sopenharmony_ci
38e41f4b71Sopenharmony_ci- Once created, a named attribute cannot have its type changed. Subsequent calls to **Set** must set a value of same type.
39e41f4b71Sopenharmony_ci- LocalStorage provides page-level storage. The [getShared](../reference/apis-arkui/arkui-ts/ts-state-management.md#getshared10) API can only obtain the LocalStorage instance passed through [windowStage.loadContent](../reference/apis-arkui/js-apis-window.md#loadcontent9) in the current stage. If the instance is not available, **undefined** is returned. For the example, see [Example of Sharing a LocalStorage Instance from UIAbility to One or More Pages](#example-of-sharing-a-localstorage-instance-from-uiability-to-one-or-more-pages).
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci## \@LocalStorageProp
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ciAs mentioned above, if you want to establish a binding between LocalStorage and a custom component, you need to use the \@LocalStorageProp and \@LocalStorageLink decorators. Specially, use \@LocalStorageProp(key) or \@LocalStorageLink(key) to decorate variables in the component, where **key** identifies the attribute in LocalStorage.
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ciWhen a custom component is initialized, the \@LocalStorageProp(key)/\@LocalStorageLink(key) decorated variable is initialized with the value of the attribute with the given key in LocalStorage. Local initialization is mandatory. If an attribute with the given key is missing from LocalStorage, it will be added with the stated initializing value. (Whether the attribute with the given key exists in LocalStorage depends on the application logic.)
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci
50e41f4b71Sopenharmony_ci> **NOTE**
51e41f4b71Sopenharmony_ci>
52e41f4b71Sopenharmony_ci> This decorator can be used in ArkTS widgets since API version 9.
53e41f4b71Sopenharmony_ci>
54e41f4b71Sopenharmony_ci> This decorator can be used in atomic services since API version 11.
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ciBy decorating a variable with \@LocalStorageProp(key), a one-way data synchronization is established from the attribute with the given key in LocalStorage to the variable. This means that, local changes (if any) will not be synchronized to LocalStorage, and an update to the attribute with the given key in LocalStorage – for example, a change made with the **set** API – will overwrite local changes.
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci### Rules of Use
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ci| \@LocalStorageProp Decorator | Description                                      |
62e41f4b71Sopenharmony_ci| ----------------------- | ---------------------------------------- |
63e41f4b71Sopenharmony_ci| Decorator parameters                  | **key**: constant string, mandatory (the string must be quoted)                 |
64e41f4b71Sopenharmony_ci| Allowed variable types              | Object, class, string, number, Boolean, enum, and array of these types.<br>(Applicable to API version 12 or later) Map, Set, and Date types. For details about the scenarios of nested objects, see [Observed Changes and Behavior](#observed-changes-and-behavior).<br>The type must be specified. Whenever possible, use the same type as that of the corresponding attribute in LocalStorage. Otherwise, implicit type conversion occurs, causing application behavior exceptions.<br>**any** is not supported. **undefined** and **null** are supported since API version 12.<br>(Applicable to API version 12 or later) Union type of the preceding types, for example, string \| number, string \| undefined or ClassA \| null. For details, see [Union Type @LocalStorage](#union-type).<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, @LocalStorageProp("AA") a: number \| null = null is recommended; **@LocalStorageProp("AA") a: number = null** is not recommended. |
65e41f4b71Sopenharmony_ci| Synchronization type                   | One-way: from the attribute in LocalStorage to the component variable. The component variable can be changed locally, but an update from LocalStorage will overwrite local changes. |
66e41f4b71Sopenharmony_ci| Initial value for the decorated variable              | Mandatory. If the attribute does not exist in LocalStorage, it will be created and initialized with this value. |
67e41f4b71Sopenharmony_ci
68e41f4b71Sopenharmony_ci
69e41f4b71Sopenharmony_ci### Variable Transfer/Access Rules
70e41f4b71Sopenharmony_ci
71e41f4b71Sopenharmony_ci| Transfer/Access     | Description                                      |
72e41f4b71Sopenharmony_ci| ---------- | ---------------------------------------- |
73e41f4b71Sopenharmony_ci| Initialization and update from the parent component | Forbidden. |
74e41f4b71Sopenharmony_ci| Child component initialization    | Supported. The \@LocalStorageProp decorated variable can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component. |
75e41f4b71Sopenharmony_ci| Access from outside the component | Not supported.                                      |
76e41f4b71Sopenharmony_ci
77e41f4b71Sopenharmony_ci  **Figure 1** \@LocalStorageProp initialization rule 
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci![en-us_image_0000001501936014](figures/en-us_image_0000001501936014.png)
80e41f4b71Sopenharmony_ci
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci### Observed Changes and Behavior
83e41f4b71Sopenharmony_ci
84e41f4b71Sopenharmony_ci**Observed Changes**
85e41f4b71Sopenharmony_ci
86e41f4b71Sopenharmony_ci
87e41f4b71Sopenharmony_ci- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
88e41f4b71Sopenharmony_ci
89e41f4b71Sopenharmony_ci- When the decorated variable is of the class or object type, its value change as well as value changes of all its attributes can be observed. For details, see [Example for Using LocalStorage from Inside the UI](#example-for-using-localstorage-from-inside-the-ui).
90e41f4b71Sopenharmony_ci
91e41f4b71Sopenharmony_ci- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed.
92e41f4b71Sopenharmony_ci
93e41f4b71Sopenharmony_ci- When the decorated object is of the **Date** type, the overall value changes of **Date** can be observed. In addition, you can call the following APIs to update **Date** properties: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**. For details, see [Decorating Variables of the Date Type](#decorating-variables-of-the-date-type).
94e41f4b71Sopenharmony_ci
95e41f4b71Sopenharmony_ci- 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).
96e41f4b71Sopenharmony_ci
97e41f4b71Sopenharmony_ci- 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).
98e41f4b71Sopenharmony_ci
99e41f4b71Sopenharmony_ci
100e41f4b71Sopenharmony_ci**Framework Behavior**
101e41f4b71Sopenharmony_ci
102e41f4b71Sopenharmony_ci
103e41f4b71Sopenharmony_ci- Value changes of the variables decorated by \@LocalStorageProp are not synchronized to LocalStorage.
104e41f4b71Sopenharmony_ci
105e41f4b71Sopenharmony_ci- Value changes of the variables decorated by \@LocalStorageProp will cause a re-render of components associated with the current custom component.
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ci- When an attribute with the given key in LocalStorage is updated, the change is synchronized to all the \@LocalStorageProp(key) decorated variables and overwrite all local changes of these variables.
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci![LocalStorageProp_framework_behavior](figures/LocalStorageProp_framework_behavior.png)
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci
112e41f4b71Sopenharmony_ci## \@LocalStorageLink
113e41f4b71Sopenharmony_ci
114e41f4b71Sopenharmony_ci> **NOTE**
115e41f4b71Sopenharmony_ci>
116e41f4b71Sopenharmony_ci> This decorator can be used in atomic services since API version 11.
117e41f4b71Sopenharmony_ci
118e41f4b71Sopenharmony_ci\@LocalStorageLink is required if you need to synchronize the changes of the state variables in a custom component back to LocalStorage.
119e41f4b71Sopenharmony_ci
120e41f4b71Sopenharmony_ci\@LocalStorageLink(key) creates a two-way data synchronization with the attribute with the given key in LocalStorage.
121e41f4b71Sopenharmony_ci
122e41f4b71Sopenharmony_ci1. If a local change occurs, it is synchronized to LocalStorage.
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci2. Changes in LocalStorage are synchronized to all attributes with the given key, including one-way bound variables (\@LocalStorageProp decorated variables and one-way bound variables created through \@Prop) and two-way bound variables (\@LocalStorageLink decorated variables and two-way bound variables created through \@Link).
125e41f4b71Sopenharmony_ci
126e41f4b71Sopenharmony_ci### Rules of Use
127e41f4b71Sopenharmony_ci
128e41f4b71Sopenharmony_ci| \@LocalStorageLink Decorator | Description                                      |
129e41f4b71Sopenharmony_ci| ----------------------- | ---------------------------------------- |
130e41f4b71Sopenharmony_ci| Decorator parameters                  | **key**: constant string, mandatory (the string must be quoted)                 |
131e41f4b71Sopenharmony_ci| Allowed variable types              | Object, class, string, number, Boolean, enum, and array of these types.<br>(Applicable to API version 12 or later) Map, Set, and Date types. For details about the scenarios of nested objects, see [Observed Changes and Behavior](#observed-changes-and-behavior).<br>The type must be specified. Whenever possible, use the same type as that of the corresponding attribute in LocalStorage. Otherwise, implicit type conversion occurs, causing application behavior exceptions.<br>**any** is not supported. **undefined** and **null** are supported since API version 12.<br>(Applicable to API version 12 or later) Union type of the preceding types, for example, string \| number, string \| undefined or ClassA \| null. For details, see [Union Type @LocalStorage](#union-type).<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, @LocalStorageLink("AA") a: number \| null = null is recommended. **@LocalStorageLink("AA") a: number = null** is not recommended. |
132e41f4b71Sopenharmony_ci| Synchronization type                   | Two-way: from the attribute in LocalStorage to the custom component variable and back |
133e41f4b71Sopenharmony_ci| Initial value for the decorated variable              | Mandatory. If the attribute does not exist in LocalStorage, it will be created and initialized with this value. |
134e41f4b71Sopenharmony_ci
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci### Variable Transfer/Access Rules
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ci| Transfer/Access     | Description                                      |
139e41f4b71Sopenharmony_ci| ---------- | ---------------------------------------- |
140e41f4b71Sopenharmony_ci| Initialization and update from the parent component | Forbidden. |
141e41f4b71Sopenharmony_ci| Child component initialization    | Supported. The \@LocalStorageProp decorated variable can be used to initialize an \@State, \@Link, \@Prop, or \@Provide decorated variable in the child component. |
142e41f4b71Sopenharmony_ci| Access from outside the component | Not supported.                                      |
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci
145e41f4b71Sopenharmony_ci  **Figure 2** \@LocalStorageLink initialization rule 
146e41f4b71Sopenharmony_ci
147e41f4b71Sopenharmony_ci
148e41f4b71Sopenharmony_ci![en-us_image_0000001552855957](figures/en-us_image_0000001552855957.png)
149e41f4b71Sopenharmony_ci
150e41f4b71Sopenharmony_ci
151e41f4b71Sopenharmony_ci### Observed Changes and Behavior
152e41f4b71Sopenharmony_ci
153e41f4b71Sopenharmony_ci**Observed Changes**
154e41f4b71Sopenharmony_ci
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci- When the decorated variable is of the class or object type, its value change as well as value changes of all its attributes can be observed. For details, see [Example for Using LocalStorage from Inside the UI](#example-for-using-localstorage-from-inside-the-ui).
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed.
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci- When the decorated object is of the **Date** type, the overall value changes of **Date** can be observed. In addition, you can call the following APIs to update **Date** properties: **setFullYear**, **setMonth**, **setDate**, **setHours**, **setMinutes**, **setSeconds**, **setMilliseconds**, **setTime**, **setUTCFullYear**, **setUTCMonth**, **setUTCDate**, **setUTCHours**, **setUTCMinutes**, **setUTCSeconds**, and **setUTCMilliseconds**. For details, see [Decorating Variables of the Date Type](#decorating-variables-of-the-date-type).
163e41f4b71Sopenharmony_ci
164e41f4b71Sopenharmony_ci- 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).
165e41f4b71Sopenharmony_ci
166e41f4b71Sopenharmony_ci- 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).
167e41f4b71Sopenharmony_ci
168e41f4b71Sopenharmony_ci
169e41f4b71Sopenharmony_ci**Framework Behavior**
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci
172e41f4b71Sopenharmony_ci1. When the value change of the \@LocalStorageLink(key) decorated variable is observed, the change is synchronized to the attribute with the give key value in LocalStorage.
173e41f4b71Sopenharmony_ci
174e41f4b71Sopenharmony_ci2. Once the attribute with the given key in LocalStorage is updated, all the data (including \@LocalStorageLink and \@LocalStorageProp decorated variables) bound to the attribute key is changed synchronously.
175e41f4b71Sopenharmony_ci
176e41f4b71Sopenharmony_ci3. When the data decorated by \@LocalStorageLink(key) is a state variable, the change of the data is synchronized to LocalStorage, and the owning custom component is re-rendered.
177e41f4b71Sopenharmony_ci
178e41f4b71Sopenharmony_ci![LocalStorageLink_framework_behavior](figures/LocalStorageLink_framework_behavior.png)
179e41f4b71Sopenharmony_ci
180e41f4b71Sopenharmony_ci
181e41f4b71Sopenharmony_ci## Use Scenarios
182e41f4b71Sopenharmony_ci
183e41f4b71Sopenharmony_ci
184e41f4b71Sopenharmony_ci### Example of Using LocalStorage in Application Logic
185e41f4b71Sopenharmony_ci
186e41f4b71Sopenharmony_ci
187e41f4b71Sopenharmony_ci```ts
188e41f4b71Sopenharmony_cilet para: Record<string,number> = { 'PropA': 47 };
189e41f4b71Sopenharmony_cilet storage: LocalStorage = new LocalStorage(para); // Create an instance and initialize it with the given object.
190e41f4b71Sopenharmony_cilet propA: number | undefined = storage.get('PropA') // propA == 47
191e41f4b71Sopenharmony_cilet link1: SubscribedAbstractProperty<number> = storage.link('PropA'); // link1.get() == 47
192e41f4b71Sopenharmony_cilet link2: SubscribedAbstractProperty<number> = storage.link('PropA'); // link2.get() == 47
193e41f4b71Sopenharmony_cilet prop: SubscribedAbstractProperty<number> = storage.prop('PropA'); // prop.get() == 47
194e41f4b71Sopenharmony_cilink1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
195e41f4b71Sopenharmony_ciprop.set(1); // one-way sync: prop.get() == 1; but link1.get() == link2.get() == 48
196e41f4b71Sopenharmony_cilink1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
197e41f4b71Sopenharmony_ci```
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci
200e41f4b71Sopenharmony_ci### Example for Using LocalStorage from Inside the UI
201e41f4b71Sopenharmony_ci
202e41f4b71Sopenharmony_ciThe two decorators \@LocalStorageProp and \@LocalStorageLink can work together to obtain the state variable stored in a LocalStorage instance in the UI component.
203e41f4b71Sopenharmony_ci
204e41f4b71Sopenharmony_ciThis example uses \@LocalStorageLink to implement the following:
205e41f4b71Sopenharmony_ci
206e41f4b71Sopenharmony_ci- Use the **build** function to create a LocalStorage instance named **storage**.
207e41f4b71Sopenharmony_ci
208e41f4b71Sopenharmony_ci- Use the \@Entry decorator to add **storage** to the top-level component **CompA**.
209e41f4b71Sopenharmony_ci
210e41f4b71Sopenharmony_ci- Use \@LocalStorageLink to create a two-way data synchronization with the given attribute in LocalStorage.
211e41f4b71Sopenharmony_ci
212e41f4b71Sopenharmony_ci ```ts
213e41f4b71Sopenharmony_ciclass PropB {
214e41f4b71Sopenharmony_ci  code: number;
215e41f4b71Sopenharmony_ci
216e41f4b71Sopenharmony_ci  constructor(code: number) {
217e41f4b71Sopenharmony_ci    this.code = code;
218e41f4b71Sopenharmony_ci  }
219e41f4b71Sopenharmony_ci}
220e41f4b71Sopenharmony_ci// Create a new instance and initialize it with the given object.
221e41f4b71Sopenharmony_cilet para: Record<string, number> = { 'PropA': 47 };
222e41f4b71Sopenharmony_cilet storage: LocalStorage = new LocalStorage(para);
223e41f4b71Sopenharmony_cistorage.setOrCreate('PropB', new PropB(50));
224e41f4b71Sopenharmony_ci
225e41f4b71Sopenharmony_ci@Component
226e41f4b71Sopenharmony_cistruct Child {
227e41f4b71Sopenharmony_ci  // @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
228e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') childLinkNumber: number = 1;
229e41f4b71Sopenharmony_ci  // @LocalStorageLink creates a two-way data synchronization with the PropB attribute in LocalStorage.
230e41f4b71Sopenharmony_ci  @LocalStorageLink('PropB') childLinkObject: PropB = new PropB(0);
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci  build() {
233e41f4b71Sopenharmony_ci    Column() {
234e41f4b71Sopenharmony_ci      Button(`Child from LocalStorage ${this.childLinkNumber}`) // The changes will be synchronized to PropA in LocalStorage and with Parent.parentLinkNumber.
235e41f4b71Sopenharmony_ci        .onClick(() => {
236e41f4b71Sopenharmony_ci          this.childLinkNumber += 1;
237e41f4b71Sopenharmony_ci        })
238e41f4b71Sopenharmony_ci      Button(`Child from LocalStorage ${this.childLinkObject.code}`) // The changes will be synchronized to PropB in LocalStorage and with Parent.parentLinkObject.code.
239e41f4b71Sopenharmony_ci        .onClick(() => {
240e41f4b71Sopenharmony_ci          this.childLinkObject.code += 1;
241e41f4b71Sopenharmony_ci        })
242e41f4b71Sopenharmony_ci    }
243e41f4b71Sopenharmony_ci  }
244e41f4b71Sopenharmony_ci}
245e41f4b71Sopenharmony_ci// Make LocalStorage accessible from the @Component decorated component.
246e41f4b71Sopenharmony_ci@Entry(storage)
247e41f4b71Sopenharmony_ci@Component
248e41f4b71Sopenharmony_cistruct CompA {
249e41f4b71Sopenharmony_ci  // @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
250e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') parentLinkNumber: number = 1;
251e41f4b71Sopenharmony_ci  // @LocalStorageLink creates a two-way data synchronization with the PropB attribute in LocalStorage.
252e41f4b71Sopenharmony_ci  @LocalStorageLink('PropB') parentLinkObject: PropB = new PropB(0);
253e41f4b71Sopenharmony_ci
254e41f4b71Sopenharmony_ci  build() {
255e41f4b71Sopenharmony_ci    Column({ space: 15 }) {
256e41f4b71Sopenharmony_ci      Button(`Parent from LocalStorage ${this.parentLinkNumber}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
257e41f4b71Sopenharmony_ci        .onClick(() => {
258e41f4b71Sopenharmony_ci          this.parentLinkNumber += 1;
259e41f4b71Sopenharmony_ci        })
260e41f4b71Sopenharmony_ci
261e41f4b71Sopenharmony_ci      Button(`Parent from LocalStorage ${this.parentLinkObject.code}`) // initial value from LocalStorage will be 50, because 'PropB' initialized already
262e41f4b71Sopenharmony_ci        .onClick(() => {
263e41f4b71Sopenharmony_ci          this.parentLinkObject.code += 1;
264e41f4b71Sopenharmony_ci        })
265e41f4b71Sopenharmony_ci      // The @Component decorated child component automatically obtains access to the CompA LocalStorage instance.
266e41f4b71Sopenharmony_ci      Child()
267e41f4b71Sopenharmony_ci    }
268e41f4b71Sopenharmony_ci  }
269e41f4b71Sopenharmony_ci}
270e41f4b71Sopenharmony_ci```
271e41f4b71Sopenharmony_ci
272e41f4b71Sopenharmony_ci
273e41f4b71Sopenharmony_ci### Simple Example of Using \@LocalStorageProp with LocalStorage
274e41f4b71Sopenharmony_ci
275e41f4b71Sopenharmony_ciIn this example, the **CompA** and **Child** components create local data that is one-way synchronized with the PropA attribute in the LocalStorage instance **storage**.
276e41f4b71Sopenharmony_ci
277e41f4b71Sopenharmony_ci- The change of **this.storageProp1** in **CompA** takes effect only in **CompA** and is not synchronized to **storage**.
278e41f4b71Sopenharmony_ci
279e41f4b71Sopenharmony_ci- In the **Child** component, the value of **storageProp2** bound to **Text** is still 47.
280e41f4b71Sopenharmony_ci
281e41f4b71Sopenharmony_ci```ts
282e41f4b71Sopenharmony_ci// Create a new instance and initialize it with the given object.
283e41f4b71Sopenharmony_cilet para: Record<string, number> = { 'PropA': 47 };
284e41f4b71Sopenharmony_cilet storage: LocalStorage = new LocalStorage(para);
285e41f4b71Sopenharmony_ci// Make LocalStorage accessible from the @Component decorated component.
286e41f4b71Sopenharmony_ci@Entry(storage)
287e41f4b71Sopenharmony_ci@Component
288e41f4b71Sopenharmony_cistruct CompA {
289e41f4b71Sopenharmony_ci  // @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
290e41f4b71Sopenharmony_ci  @LocalStorageProp('PropA') storageProp1: number = 1;
291e41f4b71Sopenharmony_ci
292e41f4b71Sopenharmony_ci  build() {
293e41f4b71Sopenharmony_ci    Column({ space: 15 }) {
294e41f4b71Sopenharmony_ci      // The initial value is 47. After the button is clicked, the value is incremented by 1. The change takes effect only in storageProp1 in the current component and is not synchronized to LocalStorage.
295e41f4b71Sopenharmony_ci      Button(`Parent from LocalStorage ${this.storageProp1}`)
296e41f4b71Sopenharmony_ci        .onClick(() => {
297e41f4b71Sopenharmony_ci          this.storageProp1 += 1
298e41f4b71Sopenharmony_ci        })
299e41f4b71Sopenharmony_ci      Child()
300e41f4b71Sopenharmony_ci    }
301e41f4b71Sopenharmony_ci  }
302e41f4b71Sopenharmony_ci}
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ci@Component
305e41f4b71Sopenharmony_cistruct Child {
306e41f4b71Sopenharmony_ci  // @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
307e41f4b71Sopenharmony_ci  @LocalStorageProp('PropA') storageProp2: number = 2;
308e41f4b71Sopenharmony_ci
309e41f4b71Sopenharmony_ci  build() {
310e41f4b71Sopenharmony_ci    Column({ space: 15 }) {
311e41f4b71Sopenharmony_ci      // When CompA changes, the current storageProp2 does not change, and 47 is displayed.
312e41f4b71Sopenharmony_ci      Text(`Parent from LocalStorage ${this.storageProp2}`)
313e41f4b71Sopenharmony_ci    }
314e41f4b71Sopenharmony_ci  }
315e41f4b71Sopenharmony_ci}
316e41f4b71Sopenharmony_ci```
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci
319e41f4b71Sopenharmony_ci### Simple Example of Using \@LocalStorageLink and LocalStorage
320e41f4b71Sopenharmony_ci
321e41f4b71Sopenharmony_ciThis example shows how to create a two-way data synchronization between an \@LocalStorageLink decorated variable and LocalStorage.
322e41f4b71Sopenharmony_ci
323e41f4b71Sopenharmony_ci
324e41f4b71Sopenharmony_ci```ts
325e41f4b71Sopenharmony_ci// Create a LocalStorage instance.
326e41f4b71Sopenharmony_cilet para: Record<string, number> = { 'PropA': 47 };
327e41f4b71Sopenharmony_cilet storage: LocalStorage = new LocalStorage(para);
328e41f4b71Sopenharmony_ci// Call the link API (available since API version 9) to create a two-way data synchronization with PropA. linkToPropA is a global variable.
329e41f4b71Sopenharmony_cilet linkToPropA: SubscribedAbstractProperty<object> = storage.link('PropA');
330e41f4b71Sopenharmony_ci
331e41f4b71Sopenharmony_ci@Entry(storage)
332e41f4b71Sopenharmony_ci@Component
333e41f4b71Sopenharmony_cistruct CompA {
334e41f4b71Sopenharmony_ci
335e41f4b71Sopenharmony_ci  // @LocalStorageLink('PropA') creates a two-way synchronization with PropA in the CompA custom component. The initial value is 47, because PropA has been set to 47 during LocalStorage construction.
336e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') storageLink: number = 1;
337e41f4b71Sopenharmony_ci
338e41f4b71Sopenharmony_ci  build() {
339e41f4b71Sopenharmony_ci    Column() {
340e41f4b71Sopenharmony_ci      Text(`incr @LocalStorageLink variable`)
341e41f4b71Sopenharmony_ci        // Clicking incr @LocalStorageLink variable increases the value of this.storageLink by 1. The change is synchronized back to the storage. The global variable linkToPropA also changes.
342e41f4b71Sopenharmony_ci
343e41f4b71Sopenharmony_ci        .onClick(() => {
344e41f4b71Sopenharmony_ci          this.storageLink += 1
345e41f4b71Sopenharmony_ci        })
346e41f4b71Sopenharmony_ci
347e41f4b71Sopenharmony_ci      // Avoid using the global variable linkToPropA.get() in the component. Doing so may cause errors due to different lifecycles.
348e41f4b71Sopenharmony_ci      Text(`@LocalStorageLink: ${this.storageLink} - linkToPropA: ${linkToPropA.get()}`)
349e41f4b71Sopenharmony_ci    }
350e41f4b71Sopenharmony_ci  }
351e41f4b71Sopenharmony_ci}
352e41f4b71Sopenharmony_ci```
353e41f4b71Sopenharmony_ci
354e41f4b71Sopenharmony_ci
355e41f4b71Sopenharmony_ci### Example of Syncing State Variables Between Sibling Components
356e41f4b71Sopenharmony_ci
357e41f4b71Sopenharmony_ciThis example shows how to use \@LocalStorageLink to create a two-way synchronization for the state between sibling components.
358e41f4b71Sopenharmony_ci
359e41f4b71Sopenharmony_ciCheck the changes in the **Parent** custom component.
360e41f4b71Sopenharmony_ci
361e41f4b71Sopenharmony_ci1. Clicking **playCount ${this.playCount} dec by 1** decreases the value of **this.playCount** by 1. This change is synchronized to LocalStorage and to the components bound to **playCountLink** in the **Child** component.
362e41f4b71Sopenharmony_ci
363e41f4b71Sopenharmony_ci2. Click **countStorage ${this.playCount} incr by 1** to call the **set** API in LocalStorage to update the attributes corresponding to **countStorage** in LocalStorage. The components bound to** playCountLink** in the **Child** component are updated synchronously.
364e41f4b71Sopenharmony_ci
365e41f4b71Sopenharmony_ci3. The **playCount in LocalStorage for debug ${storage.get&lt;number&gt;('countStorage')}** **\<Text>** component is not updated synchronously, because **storage.get<number>('countStorage')** returns a regular variable. The update of a regular variable does not cause the **\<Text>** component to be re-rendered.
366e41f4b71Sopenharmony_ci
367e41f4b71Sopenharmony_ciChanges in the **Child** custom component:
368e41f4b71Sopenharmony_ci
369e41f4b71Sopenharmony_ci1. The update of **playCountLink** is synchronized to LocalStorage, and the parent and sibling child custom components are re-rendered accordingly.
370e41f4b71Sopenharmony_ci
371e41f4b71Sopenharmony_ci```ts
372e41f4b71Sopenharmony_cilet ls: Record<string, number> = { 'countStorage': 1 }
373e41f4b71Sopenharmony_cilet storage: LocalStorage = new LocalStorage(ls);
374e41f4b71Sopenharmony_ci
375e41f4b71Sopenharmony_ci@Component
376e41f4b71Sopenharmony_cistruct Child {
377e41f4b71Sopenharmony_ci  // Name the child component instance.
378e41f4b71Sopenharmony_ci  label: string = 'no name';
379e41f4b71Sopenharmony_ci  // Two-way synchronization with countStorage in LocalStorage.
380e41f4b71Sopenharmony_ci  @LocalStorageLink('countStorage') playCountLink: number = 0;
381e41f4b71Sopenharmony_ci
382e41f4b71Sopenharmony_ci  build() {
383e41f4b71Sopenharmony_ci    Row() {
384e41f4b71Sopenharmony_ci      Text(this.label)
385e41f4b71Sopenharmony_ci        .width(50).height(60).fontSize(12)
386e41f4b71Sopenharmony_ci      Text(`playCountLink ${this.playCountLink}: inc by 1`)
387e41f4b71Sopenharmony_ci        .onClick(() => {
388e41f4b71Sopenharmony_ci          this.playCountLink += 1;
389e41f4b71Sopenharmony_ci        })
390e41f4b71Sopenharmony_ci        .width(200).height(60).fontSize(12)
391e41f4b71Sopenharmony_ci    }.width(300).height(60)
392e41f4b71Sopenharmony_ci  }
393e41f4b71Sopenharmony_ci}
394e41f4b71Sopenharmony_ci
395e41f4b71Sopenharmony_ci@Entry(storage)
396e41f4b71Sopenharmony_ci@Component
397e41f4b71Sopenharmony_cistruct Parent {
398e41f4b71Sopenharmony_ci  @LocalStorageLink('countStorage') playCount: number = 0;
399e41f4b71Sopenharmony_ci
400e41f4b71Sopenharmony_ci  build() {
401e41f4b71Sopenharmony_ci    Column() {
402e41f4b71Sopenharmony_ci      Row() {
403e41f4b71Sopenharmony_ci        Text('Parent')
404e41f4b71Sopenharmony_ci          .width(50).height(60).fontSize(12)
405e41f4b71Sopenharmony_ci        Text(`playCount ${this.playCount} dec by 1`)
406e41f4b71Sopenharmony_ci          .onClick(() => {
407e41f4b71Sopenharmony_ci            this.playCount -= 1;
408e41f4b71Sopenharmony_ci          })
409e41f4b71Sopenharmony_ci          .width(250).height(60).fontSize(12)
410e41f4b71Sopenharmony_ci      }.width(300).height(60)
411e41f4b71Sopenharmony_ci
412e41f4b71Sopenharmony_ci      Row() {
413e41f4b71Sopenharmony_ci        Text('LocalStorage')
414e41f4b71Sopenharmony_ci          .width(50).height(60).fontSize(12)
415e41f4b71Sopenharmony_ci        Text(`countStorage ${this.playCount} incr by 1`)
416e41f4b71Sopenharmony_ci          .onClick(() => {
417e41f4b71Sopenharmony_ci            storage.set<number | undefined>('countStorage', Number(storage.get<number>('countStorage')) + 1);
418e41f4b71Sopenharmony_ci          })
419e41f4b71Sopenharmony_ci          .width(250).height(60).fontSize(12)
420e41f4b71Sopenharmony_ci      }.width(300).height(60)
421e41f4b71Sopenharmony_ci
422e41f4b71Sopenharmony_ci      Child({ label: 'ChildA' })
423e41f4b71Sopenharmony_ci      Child({ label: 'ChildB' })
424e41f4b71Sopenharmony_ci
425e41f4b71Sopenharmony_ci      Text(`playCount in LocalStorage for debug ${storage.get<number>('countStorage')}`)
426e41f4b71Sopenharmony_ci        .width(300).height(60).fontSize(12)
427e41f4b71Sopenharmony_ci    }
428e41f4b71Sopenharmony_ci  }
429e41f4b71Sopenharmony_ci}
430e41f4b71Sopenharmony_ci```
431e41f4b71Sopenharmony_ci
432e41f4b71Sopenharmony_ci
433e41f4b71Sopenharmony_ci### Example of Sharing a LocalStorage Instance from UIAbility to One or More Pages
434e41f4b71Sopenharmony_ci
435e41f4b71Sopenharmony_ciIn the preceding examples, the LocalStorage instance is shared only in an \@Entry decorated component and its child component (a page). To enable a LocalStorage instance to be shared across pages, you can create a LocalStorage instance in its owning UIAbility and call windowStage.[loadContent](../reference/apis-arkui/js-apis-window.md#loadcontent9).
436e41f4b71Sopenharmony_ci
437e41f4b71Sopenharmony_ci
438e41f4b71Sopenharmony_ci```ts
439e41f4b71Sopenharmony_ci// EntryAbility.ets
440e41f4b71Sopenharmony_ciimport { UIAbility } from '@kit.AbilityKit';
441e41f4b71Sopenharmony_ciimport { window } from '@kit.ArkUI';
442e41f4b71Sopenharmony_ci
443e41f4b71Sopenharmony_ciexport default class EntryAbility extends UIAbility {
444e41f4b71Sopenharmony_cipara:Record<string, number> = { 'PropA': 47 };
445e41f4b71Sopenharmony_cistorage: LocalStorage = new LocalStorage(this.para);
446e41f4b71Sopenharmony_ci
447e41f4b71Sopenharmony_cionWindowStageCreate(windowStage: window.WindowStage) {
448e41f4b71Sopenharmony_ciwindowStage.loadContent('pages/Index', this.storage);
449e41f4b71Sopenharmony_ci}
450e41f4b71Sopenharmony_ci}
451e41f4b71Sopenharmony_ci```
452e41f4b71Sopenharmony_ci> **NOTE**
453e41f4b71Sopenharmony_ci>
454e41f4b71Sopenharmony_ci> On the page, call the **getShared** API to obtain the LocalStorage instance shared through **loadContent**.
455e41f4b71Sopenharmony_ci>
456e41f4b71Sopenharmony_ci> **LocalStorage.getShared()** works only on emulators and real devices, not in DevEco Studio Previewer.
457e41f4b71Sopenharmony_ci
458e41f4b71Sopenharmony_ci
459e41f4b71Sopenharmony_ciIn the following example, **propA** on the **Index** page uses the **getShared()** API to obtain the shared LocalStorage instance. Click the button to go to the **Page** page. Click **Change propA** and then return to the **Index** page. It can be observed that the value of **propA** on the page is changed.
460e41f4b71Sopenharmony_ci```ts
461e41f4b71Sopenharmony_ci// index.ets
462e41f4b71Sopenharmony_ciimport { router } from '@kit.ArkUI';
463e41f4b71Sopenharmony_ci
464e41f4b71Sopenharmony_ci// Use the getShared API to obtain the LocalStorage instance shared by stage.
465e41f4b71Sopenharmony_cilet storage = LocalStorage.getShared()
466e41f4b71Sopenharmony_ci
467e41f4b71Sopenharmony_ci@Entry(storage)
468e41f4b71Sopenharmony_ci@Component
469e41f4b71Sopenharmony_cistruct Index {
470e41f4b71Sopenharmony_ci  // The LocalStorage instance can be accessed using 
471e41f4b71Sopenharmony_ci  // @LocalStorageLink/Prop decorated variables.
472e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') propA: number = 1;
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci  build() {
475e41f4b71Sopenharmony_ci    Row() {
476e41f4b71Sopenharmony_ci      Column() {
477e41f4b71Sopenharmony_ci        Text(`${this.propA}`)
478e41f4b71Sopenharmony_ci          .fontSize(50)
479e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
480e41f4b71Sopenharmony_ci        Button("To Page")
481e41f4b71Sopenharmony_ci          .onClick(() => {
482e41f4b71Sopenharmony_ci            router.pushUrl({
483e41f4b71Sopenharmony_ci              url: 'pages/Page'
484e41f4b71Sopenharmony_ci            })
485e41f4b71Sopenharmony_ci          })
486e41f4b71Sopenharmony_ci      }
487e41f4b71Sopenharmony_ci      .width('100%')
488e41f4b71Sopenharmony_ci    }
489e41f4b71Sopenharmony_ci    .height('100%')
490e41f4b71Sopenharmony_ci  }
491e41f4b71Sopenharmony_ci}
492e41f4b71Sopenharmony_ci```
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ci```ts
495e41f4b71Sopenharmony_ci// Page.ets
496e41f4b71Sopenharmony_ciimport { router } from '@kit.ArkUI';
497e41f4b71Sopenharmony_ci
498e41f4b71Sopenharmony_cilet storage = LocalStorage.getShared()
499e41f4b71Sopenharmony_ci
500e41f4b71Sopenharmony_ci@Entry(storage)
501e41f4b71Sopenharmony_ci@Component
502e41f4b71Sopenharmony_cistruct Page {
503e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') propA: number = 2;
504e41f4b71Sopenharmony_ci
505e41f4b71Sopenharmony_ci  build() {
506e41f4b71Sopenharmony_ci    Row() {
507e41f4b71Sopenharmony_ci      Column() {
508e41f4b71Sopenharmony_ci        Text(`${this.propA}`)
509e41f4b71Sopenharmony_ci          .fontSize(50)
510e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
511e41f4b71Sopenharmony_ci
512e41f4b71Sopenharmony_ci        Button("Change propA")
513e41f4b71Sopenharmony_ci          .onClick(() => {
514e41f4b71Sopenharmony_ci            this.propA = 100;
515e41f4b71Sopenharmony_ci          })
516e41f4b71Sopenharmony_ci
517e41f4b71Sopenharmony_ci        Button("Back Index")
518e41f4b71Sopenharmony_ci          .onClick(() => {
519e41f4b71Sopenharmony_ci            router.back()
520e41f4b71Sopenharmony_ci          })
521e41f4b71Sopenharmony_ci      }
522e41f4b71Sopenharmony_ci      .width('100%')
523e41f4b71Sopenharmony_ci    }
524e41f4b71Sopenharmony_ci  }
525e41f4b71Sopenharmony_ci}
526e41f4b71Sopenharmony_ci```
527e41f4b71Sopenharmony_ci
528e41f4b71Sopenharmony_ci> **NOTE**
529e41f4b71Sopenharmony_ci>
530e41f4b71Sopenharmony_ci> It is good practice to always create a LocalStorage instance with meaningful default values, which serve as a backup when execution exceptions occur and are also useful for unit testing of pages.
531e41f4b71Sopenharmony_ci
532e41f4b71Sopenharmony_ci
533e41f4b71Sopenharmony_ci### Example of Providing a Custom Component with Access to a LocalStorage Instance
534e41f4b71Sopenharmony_ci
535e41f4b71Sopenharmony_ciLocalStorage instances are accessible to both root nodes through @Entry and custom components (child nodes) through constructors.
536e41f4b71Sopenharmony_ci
537e41f4b71Sopenharmony_ciThis example uses \@LocalStorageLink to implement the following:
538e41f4b71Sopenharmony_ci
539e41f4b71Sopenharmony_ci- The text in the parent component reads **PropA**, value of **PropA** in the LocalStorage instance **localStorage1**.
540e41f4b71Sopenharmony_ci
541e41f4b71Sopenharmony_ci- The text in the **Child** component reads **PropB**, value of **PropB** in the LocalStorage instance **localStorage2**.
542e41f4b71Sopenharmony_ci
543e41f4b71Sopenharmony_ci> **NOTE**
544e41f4b71Sopenharmony_ci>
545e41f4b71Sopenharmony_ci> LocalStorage instances are accessible to custom components since API version 12.
546e41f4b71Sopenharmony_ci> If a custom component functions as a subnode and has member attributes defined, a LocalStorage instance must be passed in as the second parameter. Otherwise, a type mismatch error is reported at compile time.
547e41f4b71Sopenharmony_ci> If a custom component has any attribute defined, it does not accept a LocalStorage instance as the only input parameter. If a custom component does not have any attribute defined, it can accept a LocalStorage instance as the only input parameter.
548e41f4b71Sopenharmony_ci> If the defined attribute does not need to be initialized from the parent component, {} must be passed in as the first parameter.
549e41f4b71Sopenharmony_ci> The LocalStorage instance that is passed to a child component as a constructor parameter is determined at initialization. You can use @LocalStorageLink or the API of LocalStorage to modify the attribute values stored in the LocalStorage instance, but the LocalStorage instance itself cannot be dynamically modified.
550e41f4b71Sopenharmony_ci
551e41f4b71Sopenharmony_ci```ts
552e41f4b71Sopenharmony_cilet localStorage1: LocalStorage = new LocalStorage();
553e41f4b71Sopenharmony_cilocalStorage1.setOrCreate('PropA', 'PropA');
554e41f4b71Sopenharmony_ci
555e41f4b71Sopenharmony_cilet localStorage2: LocalStorage = new LocalStorage();
556e41f4b71Sopenharmony_cilocalStorage2.setOrCreate('PropB', 'PropB');
557e41f4b71Sopenharmony_ci
558e41f4b71Sopenharmony_ci@Entry(localStorage1)
559e41f4b71Sopenharmony_ci@Component
560e41f4b71Sopenharmony_cistruct Index {
561e41f4b71Sopenharmony_ci  // PropA is in two-way synchronization with PropA in localStorage1.
562e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') PropA: string = 'Hello World';
563e41f4b71Sopenharmony_ci  @State count: number = 0;
564e41f4b71Sopenharmony_ci
565e41f4b71Sopenharmony_ci  build() {
566e41f4b71Sopenharmony_ci    Row() {
567e41f4b71Sopenharmony_ci      Column() {
568e41f4b71Sopenharmony_ci        Text(this.PropA)
569e41f4b71Sopenharmony_ci          .fontSize(50)
570e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
571e41f4b71Sopenharmony_ci        // Use the LocalStorage instance localStorage2.
572e41f4b71Sopenharmony_ci        Child({ count: this.count }, localStorage2)
573e41f4b71Sopenharmony_ci      }
574e41f4b71Sopenharmony_ci      .width('100%')
575e41f4b71Sopenharmony_ci    }
576e41f4b71Sopenharmony_ci    .height('100%')
577e41f4b71Sopenharmony_ci  }
578e41f4b71Sopenharmony_ci}
579e41f4b71Sopenharmony_ci
580e41f4b71Sopenharmony_ci
581e41f4b71Sopenharmony_ci@Component
582e41f4b71Sopenharmony_cistruct Child {
583e41f4b71Sopenharmony_ci  @Link count: number;
584e41f4b71Sopenharmony_ci  // Hello World is in two-way synchronization with PropB in localStorage2. If there is no PropB in localStorage2, the default value Hello World is used.
585e41f4b71Sopenharmony_ci  @LocalStorageLink('PropB') PropB: string = 'Hello World';
586e41f4b71Sopenharmony_ci
587e41f4b71Sopenharmony_ci  build() {
588e41f4b71Sopenharmony_ci    Text(this.PropB)
589e41f4b71Sopenharmony_ci      .fontSize(50)
590e41f4b71Sopenharmony_ci      .fontWeight(FontWeight.Bold)
591e41f4b71Sopenharmony_ci  }
592e41f4b71Sopenharmony_ci}
593e41f4b71Sopenharmony_ci```
594e41f4b71Sopenharmony_ci
595e41f4b71Sopenharmony_ci1. If a custom component does not have any attribute defined, it can accept a LocalStorage instance as the only input parameter.
596e41f4b71Sopenharmony_ci
597e41f4b71Sopenharmony_ci```ts
598e41f4b71Sopenharmony_cilet localStorage1: LocalStorage = new LocalStorage();
599e41f4b71Sopenharmony_cilocalStorage1.setOrCreate('PropA', 'PropA');
600e41f4b71Sopenharmony_ci
601e41f4b71Sopenharmony_cilet localStorage2: LocalStorage = new LocalStorage();
602e41f4b71Sopenharmony_cilocalStorage2.setOrCreate('PropB', 'PropB');
603e41f4b71Sopenharmony_ci
604e41f4b71Sopenharmony_ci@Entry(localStorage1)
605e41f4b71Sopenharmony_ci@Component
606e41f4b71Sopenharmony_cistruct Index {
607e41f4b71Sopenharmony_ci  // PropA is in two-way synchronization with PropA in localStorage1.
608e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') PropA: string = 'Hello World';
609e41f4b71Sopenharmony_ci  @State count: number = 0;
610e41f4b71Sopenharmony_ci
611e41f4b71Sopenharmony_ci  build() {
612e41f4b71Sopenharmony_ci    Row() {
613e41f4b71Sopenharmony_ci      Column() {
614e41f4b71Sopenharmony_ci        Text(this.PropA)
615e41f4b71Sopenharmony_ci          .fontSize(50)
616e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
617e41f4b71Sopenharmony_ci        // Use the LocalStorage instance localStorage2.
618e41f4b71Sopenharmony_ci        Child(localStorage2)
619e41f4b71Sopenharmony_ci      }
620e41f4b71Sopenharmony_ci      .width('100%')
621e41f4b71Sopenharmony_ci    }
622e41f4b71Sopenharmony_ci    .height('100%')
623e41f4b71Sopenharmony_ci  }
624e41f4b71Sopenharmony_ci}
625e41f4b71Sopenharmony_ci
626e41f4b71Sopenharmony_ci
627e41f4b71Sopenharmony_ci@Component
628e41f4b71Sopenharmony_cistruct Child {
629e41f4b71Sopenharmony_ci  build() {
630e41f4b71Sopenharmony_ci    Text("hello")
631e41f4b71Sopenharmony_ci      .fontSize(50)
632e41f4b71Sopenharmony_ci      .fontWeight(FontWeight.Bold)
633e41f4b71Sopenharmony_ci  }
634e41f4b71Sopenharmony_ci}
635e41f4b71Sopenharmony_ci```
636e41f4b71Sopenharmony_ci
637e41f4b71Sopenharmony_ci2. If the defined attribute does not need to be initialized from the parent component, {} must be passed in as the first parameter.
638e41f4b71Sopenharmony_ci
639e41f4b71Sopenharmony_ci```ts
640e41f4b71Sopenharmony_cilet localStorage1: LocalStorage = new LocalStorage();
641e41f4b71Sopenharmony_cilocalStorage1.setOrCreate('PropA', 'PropA');
642e41f4b71Sopenharmony_ci
643e41f4b71Sopenharmony_cilet localStorage2: LocalStorage = new LocalStorage();
644e41f4b71Sopenharmony_cilocalStorage2.setOrCreate('PropB', 'PropB');
645e41f4b71Sopenharmony_ci
646e41f4b71Sopenharmony_ci@Entry(localStorage1)
647e41f4b71Sopenharmony_ci@Component
648e41f4b71Sopenharmony_cistruct Index {
649e41f4b71Sopenharmony_ci  // PropA is in two-way synchronization with PropA in localStorage1.
650e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') PropA: string = 'Hello World';
651e41f4b71Sopenharmony_ci  @State count: number = 0;
652e41f4b71Sopenharmony_ci
653e41f4b71Sopenharmony_ci  build() {
654e41f4b71Sopenharmony_ci    Row() {
655e41f4b71Sopenharmony_ci      Column() {
656e41f4b71Sopenharmony_ci        Text(this.PropA)
657e41f4b71Sopenharmony_ci          .fontSize(50)
658e41f4b71Sopenharmony_ci          .fontWeight(FontWeight.Bold)
659e41f4b71Sopenharmony_ci        // Use the LocalStorage instance localStorage2.
660e41f4b71Sopenharmony_ci        Child({}, localStorage2)
661e41f4b71Sopenharmony_ci      }
662e41f4b71Sopenharmony_ci      .width('100%')
663e41f4b71Sopenharmony_ci    }
664e41f4b71Sopenharmony_ci    .height('100%')
665e41f4b71Sopenharmony_ci  }
666e41f4b71Sopenharmony_ci}
667e41f4b71Sopenharmony_ci
668e41f4b71Sopenharmony_ci
669e41f4b71Sopenharmony_ci@Component
670e41f4b71Sopenharmony_cistruct Child {
671e41f4b71Sopenharmony_ci  @State count: number = 5;
672e41f4b71Sopenharmony_ci  // Hello World is in two-way synchronization with PropB in localStorage2. If there is no PropB in localStorage2, the default value Hello World is used.
673e41f4b71Sopenharmony_ci  @LocalStorageLink('PropB') PropB: string = 'Hello World';
674e41f4b71Sopenharmony_ci
675e41f4b71Sopenharmony_ci  build() {
676e41f4b71Sopenharmony_ci    Text(this.PropB)
677e41f4b71Sopenharmony_ci      .fontSize(50)
678e41f4b71Sopenharmony_ci      .fontWeight(FontWeight.Bold)
679e41f4b71Sopenharmony_ci  }
680e41f4b71Sopenharmony_ci}
681e41f4b71Sopenharmony_ci```
682e41f4b71Sopenharmony_ci
683e41f4b71Sopenharmony_ci
684e41f4b71Sopenharmony_ci### Using LocalStorage with a Navigation Component
685e41f4b71Sopenharmony_ci
686e41f4b71Sopenharmony_ciYou can pass multiple LocalStorage instances to a custom component and bind them to different target navigation pages, which can then display the attribute values of the bound instances.
687e41f4b71Sopenharmony_ci
688e41f4b71Sopenharmony_ciThis example uses \@LocalStorageLink to implement the following:
689e41f4b71Sopenharmony_ci
690e41f4b71Sopenharmony_ci- Clicking **Next Page** in the parent component creates and redirects to the page named **pageOne**. The text displayed on the page is the value of **PropA** bound to the LocalStorage instance **localStorageA**, that is, **PropA**.
691e41f4b71Sopenharmony_ci
692e41f4b71Sopenharmony_ci- Clicking **Next Page** on the page creates and redirects to the page named **pageTwo**. The text displayed on the page is the value of **PropB** bound to the LocalStorage instance **localStorageB**, that is, **PropB**.
693e41f4b71Sopenharmony_ci
694e41f4b71Sopenharmony_ci- Clicking **Next Page** on the page again creates and redirects to the page named **pageTree**. The text displayed on the page is the value of **PropC** bound to the LocalStorage instance **localStorageC**, that is, **PropC**.
695e41f4b71Sopenharmony_ci
696e41f4b71Sopenharmony_ci- Clicking **Next Page** on the page again creates and redirects to the page named **pageOne**. The text displayed on the page is the value of **PropA** bound to the LocalStorage instance **localStorageA**, that is, **PropA**.
697e41f4b71Sopenharmony_ci
698e41f4b71Sopenharmony_ci- The **Text** component in the **NavigationContentMsgStack** custom component shares the value of **PropA** bound to the LocalStorage instance in the custom component tree.
699e41f4b71Sopenharmony_ci
700e41f4b71Sopenharmony_ci
701e41f4b71Sopenharmony_ci```ts
702e41f4b71Sopenharmony_cilet localStorageA: LocalStorage = new LocalStorage();
703e41f4b71Sopenharmony_cilocalStorageA.setOrCreate('PropA', 'PropA');
704e41f4b71Sopenharmony_ci
705e41f4b71Sopenharmony_cilet localStorageB: LocalStorage = new LocalStorage();
706e41f4b71Sopenharmony_cilocalStorageB.setOrCreate('PropB', 'PropB');
707e41f4b71Sopenharmony_ci
708e41f4b71Sopenharmony_cilet localStorageC: LocalStorage = new LocalStorage();
709e41f4b71Sopenharmony_cilocalStorageC.setOrCreate('PropC', 'PropC');
710e41f4b71Sopenharmony_ci
711e41f4b71Sopenharmony_ci@Entry
712e41f4b71Sopenharmony_ci@Component
713e41f4b71Sopenharmony_cistruct MyNavigationTestStack {
714e41f4b71Sopenharmony_ci  @Provide('pageInfo') pageInfo: NavPathStack = new NavPathStack();
715e41f4b71Sopenharmony_ci
716e41f4b71Sopenharmony_ci  @Builder
717e41f4b71Sopenharmony_ci  PageMap(name: string) {
718e41f4b71Sopenharmony_ci    if (name === 'pageOne') {
719e41f4b71Sopenharmony_ci      // Pass multiple LocalStorage instances.
720e41f4b71Sopenharmony_ci      pageOneStack({}, localStorageA)
721e41f4b71Sopenharmony_ci    } else if (name === 'pageTwo') {
722e41f4b71Sopenharmony_ci      pageTwoStack({}, localStorageB)
723e41f4b71Sopenharmony_ci    } else if (name === 'pageThree') {
724e41f4b71Sopenharmony_ci      pageThreeStack({}, localStorageC)
725e41f4b71Sopenharmony_ci    }
726e41f4b71Sopenharmony_ci  }
727e41f4b71Sopenharmony_ci
728e41f4b71Sopenharmony_ci  build() {
729e41f4b71Sopenharmony_ci    Column({ space: 5 }) {
730e41f4b71Sopenharmony_ci      Navigation(this.pageInfo) {
731e41f4b71Sopenharmony_ci        Column() {
732e41f4b71Sopenharmony_ci          Button('Next Page', { stateEffect: true, type: ButtonType.Capsule })
733e41f4b71Sopenharmony_ci            .width('80%')
734e41f4b71Sopenharmony_ci            .height(40)
735e41f4b71Sopenharmony_ci            .margin(20)
736e41f4b71Sopenharmony_ci            .onClick(() => {
737e41f4b71Sopenharmony_ci              this.pageInfo.pushPath({ name: 'pageOne' }); // Push the navigation destination page specified by name to the navigation stack.
738e41f4b71Sopenharmony_ci            })
739e41f4b71Sopenharmony_ci        }
740e41f4b71Sopenharmony_ci      }.title('NavIndex')
741e41f4b71Sopenharmony_ci      .navDestination(this.PageMap)
742e41f4b71Sopenharmony_ci      .mode(NavigationMode.Stack)
743e41f4b71Sopenharmony_ci      .borderWidth(1)
744e41f4b71Sopenharmony_ci    }
745e41f4b71Sopenharmony_ci  }
746e41f4b71Sopenharmony_ci}
747e41f4b71Sopenharmony_ci
748e41f4b71Sopenharmony_ci@Component
749e41f4b71Sopenharmony_cistruct pageOneStack {
750e41f4b71Sopenharmony_ci  @Consume('pageInfo') pageInfo: NavPathStack;
751e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') PropA: string = 'Hello World';
752e41f4b71Sopenharmony_ci
753e41f4b71Sopenharmony_ci  build() {
754e41f4b71Sopenharmony_ci    NavDestination() {
755e41f4b71Sopenharmony_ci      Column() {
756e41f4b71Sopenharmony_ci        NavigationContentMsgStack()
757e41f4b71Sopenharmony_ci        // Display the value of PropA in the bound LocalStorage instance.
758e41f4b71Sopenharmony_ci        Text(`${this.PropA}`)
759e41f4b71Sopenharmony_ci        Button('Next Page', { stateEffect: true, type: ButtonType.Capsule })
760e41f4b71Sopenharmony_ci          .width('80%')
761e41f4b71Sopenharmony_ci          .height(40)
762e41f4b71Sopenharmony_ci          .margin(20)
763e41f4b71Sopenharmony_ci          .onClick(() => {
764e41f4b71Sopenharmony_ci            this.pageInfo.pushPathByName('pageTwo', null);
765e41f4b71Sopenharmony_ci          })
766e41f4b71Sopenharmony_ci      }.width('100%').height('100%')
767e41f4b71Sopenharmony_ci    }.title('pageOne')
768e41f4b71Sopenharmony_ci    .onBackPressed(() => {
769e41f4b71Sopenharmony_ci      this.pageInfo.pop();
770e41f4b71Sopenharmony_ci      return true;
771e41f4b71Sopenharmony_ci    })
772e41f4b71Sopenharmony_ci  }
773e41f4b71Sopenharmony_ci}
774e41f4b71Sopenharmony_ci
775e41f4b71Sopenharmony_ci@Component
776e41f4b71Sopenharmony_cistruct pageTwoStack {
777e41f4b71Sopenharmony_ci  @Consume('pageInfo') pageInfo: NavPathStack;
778e41f4b71Sopenharmony_ci  @LocalStorageLink('PropB') PropB: string = 'Hello World';
779e41f4b71Sopenharmony_ci
780e41f4b71Sopenharmony_ci  build() {
781e41f4b71Sopenharmony_ci    NavDestination() {
782e41f4b71Sopenharmony_ci      Column() {
783e41f4b71Sopenharmony_ci        NavigationContentMsgStack()
784e41f4b71Sopenharmony_ci        // There is no PropA in the bound LocalStorage instance, and therefore the locally initialized value Hello World is displayed.
785e41f4b71Sopenharmony_ci        Text(`${this.PropB}`)
786e41f4b71Sopenharmony_ci        Button('Next Page', { stateEffect: true, type: ButtonType.Capsule })
787e41f4b71Sopenharmony_ci          .width('80%')
788e41f4b71Sopenharmony_ci          .height(40)
789e41f4b71Sopenharmony_ci          .margin(20)
790e41f4b71Sopenharmony_ci          .onClick(() => {
791e41f4b71Sopenharmony_ci            this.pageInfo.pushPathByName('pageThree', null);
792e41f4b71Sopenharmony_ci          })
793e41f4b71Sopenharmony_ci
794e41f4b71Sopenharmony_ci      }.width('100%').height('100%')
795e41f4b71Sopenharmony_ci    }.title('pageTwo')
796e41f4b71Sopenharmony_ci    .onBackPressed(() => {
797e41f4b71Sopenharmony_ci      this.pageInfo.pop();
798e41f4b71Sopenharmony_ci      return true;
799e41f4b71Sopenharmony_ci    })
800e41f4b71Sopenharmony_ci  }
801e41f4b71Sopenharmony_ci}
802e41f4b71Sopenharmony_ci
803e41f4b71Sopenharmony_ci@Component
804e41f4b71Sopenharmony_cistruct pageThreeStack {
805e41f4b71Sopenharmony_ci  @Consume('pageInfo') pageInfo: NavPathStack;
806e41f4b71Sopenharmony_ci  @LocalStorageLink('PropC') PropC: string = 'pageThreeStack';
807e41f4b71Sopenharmony_ci
808e41f4b71Sopenharmony_ci  build() {
809e41f4b71Sopenharmony_ci    NavDestination() {
810e41f4b71Sopenharmony_ci      Column() {
811e41f4b71Sopenharmony_ci        NavigationContentMsgStack()
812e41f4b71Sopenharmony_ci
813e41f4b71Sopenharmony_ci        // There is no PropA in the bound LocalStorage instance, and therefore the locally initialized value pageThreeStack is displayed.
814e41f4b71Sopenharmony_ci        Text(`${this.PropC}`)
815e41f4b71Sopenharmony_ci        Button('Next Page', { stateEffect: true, type: ButtonType.Capsule })
816e41f4b71Sopenharmony_ci          .width('80%')
817e41f4b71Sopenharmony_ci          .height(40)
818e41f4b71Sopenharmony_ci          .margin(20)
819e41f4b71Sopenharmony_ci          .onClick(() => {
820e41f4b71Sopenharmony_ci            this.pageInfo.pushPathByName('pageOne', null);
821e41f4b71Sopenharmony_ci          })
822e41f4b71Sopenharmony_ci
823e41f4b71Sopenharmony_ci      }.width('100%').height('100%')
824e41f4b71Sopenharmony_ci    }.title('pageThree')
825e41f4b71Sopenharmony_ci    .onBackPressed(() => {
826e41f4b71Sopenharmony_ci      this.pageInfo.pop();
827e41f4b71Sopenharmony_ci      return true;
828e41f4b71Sopenharmony_ci    })
829e41f4b71Sopenharmony_ci  }
830e41f4b71Sopenharmony_ci}
831e41f4b71Sopenharmony_ci
832e41f4b71Sopenharmony_ci@Component
833e41f4b71Sopenharmony_cistruct NavigationContentMsgStack {
834e41f4b71Sopenharmony_ci  @LocalStorageLink('PropA') PropA: string = 'Hello';
835e41f4b71Sopenharmony_ci
836e41f4b71Sopenharmony_ci  build() {
837e41f4b71Sopenharmony_ci    Column() {
838e41f4b71Sopenharmony_ci      Text(`${this.PropA}`)
839e41f4b71Sopenharmony_ci        .fontSize(30)
840e41f4b71Sopenharmony_ci        .fontWeight(FontWeight.Bold)
841e41f4b71Sopenharmony_ci    }
842e41f4b71Sopenharmony_ci  }
843e41f4b71Sopenharmony_ci}
844e41f4b71Sopenharmony_ci```
845e41f4b71Sopenharmony_ci
846e41f4b71Sopenharmony_ci
847e41f4b71Sopenharmony_ci### Union Type
848e41f4b71Sopenharmony_ci
849e41f4b71Sopenharmony_ciIn the following example, the type of variable **A** is number | null, and the type of variable **B** is number | undefined. The **Text** components display **null** and **undefined** upon initialization, numbers when clicked, and **null** and **undefined** when clicked again.
850e41f4b71Sopenharmony_ci
851e41f4b71Sopenharmony_ci```ts
852e41f4b71Sopenharmony_ci@Component
853e41f4b71Sopenharmony_cistruct LocalStorLink {
854e41f4b71Sopenharmony_ci  @LocalStorageLink("AA") A: number | null = null;
855e41f4b71Sopenharmony_ci  @LocalStorageLink("BB") B: number | undefined = undefined;
856e41f4b71Sopenharmony_ci
857e41f4b71Sopenharmony_ci  build() {
858e41f4b71Sopenharmony_ci    Column() {
859e41f4b71Sopenharmony_ci      Text("@LocalStorageLink initialization, @LocalStorageLink value")
860e41f4b71Sopenharmony_ci      Text(this.A + "").fontSize(20).onClick(() => {
861e41f4b71Sopenharmony_ci        this.A ? this.A = null : this.A = 1;
862e41f4b71Sopenharmony_ci      })
863e41f4b71Sopenharmony_ci      Text(this.B + "").fontSize(20).onClick(() => {
864e41f4b71Sopenharmony_ci        this.B ? this.B = undefined : this.B = 1;
865e41f4b71Sopenharmony_ci      })
866e41f4b71Sopenharmony_ci    }
867e41f4b71Sopenharmony_ci    .borderWidth(3).borderColor(Color.Green)
868e41f4b71Sopenharmony_ci
869e41f4b71Sopenharmony_ci  }
870e41f4b71Sopenharmony_ci}
871e41f4b71Sopenharmony_ci
872e41f4b71Sopenharmony_ci@Component
873e41f4b71Sopenharmony_cistruct LocalStorProp {
874e41f4b71Sopenharmony_ci  @LocalStorageProp("AAA") A: number | null = null;
875e41f4b71Sopenharmony_ci  @LocalStorageProp("BBB") B: number | undefined = undefined;
876e41f4b71Sopenharmony_ci
877e41f4b71Sopenharmony_ci  build() {
878e41f4b71Sopenharmony_ci    Column() {
879e41f4b71Sopenharmony_ci      Text("@LocalStorageProp initialization, @LocalStorageProp value")
880e41f4b71Sopenharmony_ci      Text(this.A + "").fontSize(20).onClick(() => {
881e41f4b71Sopenharmony_ci        this.A ? this.A = null : this.A = 1;
882e41f4b71Sopenharmony_ci      })
883e41f4b71Sopenharmony_ci      Text(this.B + "").fontSize(20).onClick(() => {
884e41f4b71Sopenharmony_ci        this.B ? this.B = undefined : this.B = 1;
885e41f4b71Sopenharmony_ci      })
886e41f4b71Sopenharmony_ci    }
887e41f4b71Sopenharmony_ci    .borderWidth(3).borderColor(Color.Yellow)
888e41f4b71Sopenharmony_ci
889e41f4b71Sopenharmony_ci  }
890e41f4b71Sopenharmony_ci}
891e41f4b71Sopenharmony_ci
892e41f4b71Sopenharmony_cilet storage1: LocalStorage = new LocalStorage();
893e41f4b71Sopenharmony_ci
894e41f4b71Sopenharmony_ci@Entry(storage1)
895e41f4b71Sopenharmony_ci@Component
896e41f4b71Sopenharmony_cistruct TestCase3 {
897e41f4b71Sopenharmony_ci  build() {
898e41f4b71Sopenharmony_ci    Row() {
899e41f4b71Sopenharmony_ci      Column() {
900e41f4b71Sopenharmony_ci        LocalStorLink()
901e41f4b71Sopenharmony_ci        LocalStorProp()
902e41f4b71Sopenharmony_ci      }
903e41f4b71Sopenharmony_ci      .width('100%')
904e41f4b71Sopenharmony_ci    }
905e41f4b71Sopenharmony_ci    .height('100%')
906e41f4b71Sopenharmony_ci  }
907e41f4b71Sopenharmony_ci}
908e41f4b71Sopenharmony_ci```
909e41f4b71Sopenharmony_ci
910e41f4b71Sopenharmony_ci
911e41f4b71Sopenharmony_ci### Decorating Variables of the Date Type
912e41f4b71Sopenharmony_ci
913e41f4b71Sopenharmony_ci> **NOTE**
914e41f4b71Sopenharmony_ci>
915e41f4b71Sopenharmony_ci> LocalStorage supports the Date type since API version 12.
916e41f4b71Sopenharmony_ci
917e41f4b71Sopenharmony_ciIn this example, the **selectedDate** variable decorated by @LocalStorageLink is of the Date type. After the button is clicked, the value of **selectedDate** changes, and the UI is re-rendered.
918e41f4b71Sopenharmony_ci
919e41f4b71Sopenharmony_ci```ts
920e41f4b71Sopenharmony_ci@Entry
921e41f4b71Sopenharmony_ci@Component
922e41f4b71Sopenharmony_cistruct LocalDateSample {
923e41f4b71Sopenharmony_ci  @LocalStorageLink("date") selectedDate: Date = new Date('2021-08-08');
924e41f4b71Sopenharmony_ci
925e41f4b71Sopenharmony_ci  build() {
926e41f4b71Sopenharmony_ci    Column() {
927e41f4b71Sopenharmony_ci      Button('set selectedDate to 2023-07-08')
928e41f4b71Sopenharmony_ci        .margin(10)
929e41f4b71Sopenharmony_ci        .onClick(() => {
930e41f4b71Sopenharmony_ci          this.selectedDate = new Date('2023-07-08');
931e41f4b71Sopenharmony_ci        })
932e41f4b71Sopenharmony_ci      Button('increase the year by 1')
933e41f4b71Sopenharmony_ci        .margin(10)
934e41f4b71Sopenharmony_ci        .onClick(() => {
935e41f4b71Sopenharmony_ci          this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
936e41f4b71Sopenharmony_ci        })
937e41f4b71Sopenharmony_ci      Button('increase the month by 1')
938e41f4b71Sopenharmony_ci        .margin(10)
939e41f4b71Sopenharmony_ci        .onClick(() => {
940e41f4b71Sopenharmony_ci          this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
941e41f4b71Sopenharmony_ci        })
942e41f4b71Sopenharmony_ci      Button('increase the day by 1')
943e41f4b71Sopenharmony_ci        .margin(10)
944e41f4b71Sopenharmony_ci        .onClick(() => {
945e41f4b71Sopenharmony_ci          this.selectedDate.setDate(this.selectedDate.getDate() + 1);
946e41f4b71Sopenharmony_ci        })
947e41f4b71Sopenharmony_ci      DatePicker({
948e41f4b71Sopenharmony_ci        start: new Date('1970-1-1'),
949e41f4b71Sopenharmony_ci        end: new Date('2100-1-1'),
950e41f4b71Sopenharmony_ci        selected: $$this.selectedDate
951e41f4b71Sopenharmony_ci      })
952e41f4b71Sopenharmony_ci    }.width('100%')
953e41f4b71Sopenharmony_ci  }
954e41f4b71Sopenharmony_ci}
955e41f4b71Sopenharmony_ci```
956e41f4b71Sopenharmony_ci
957e41f4b71Sopenharmony_ci
958e41f4b71Sopenharmony_ci### Decorating Variables of the Map Type
959e41f4b71Sopenharmony_ci
960e41f4b71Sopenharmony_ci> **NOTE**
961e41f4b71Sopenharmony_ci>
962e41f4b71Sopenharmony_ci> LocalStorage supports the Map type since API version 12.
963e41f4b71Sopenharmony_ci
964e41f4b71Sopenharmony_ciIn this example, the **message** variable decorated by @LocalStorageLink is of the Map\<number, string\> type. After the button is clicked, the value of **message** changes, and the UI is re-rendered.
965e41f4b71Sopenharmony_ci
966e41f4b71Sopenharmony_ci```ts
967e41f4b71Sopenharmony_ci@Entry
968e41f4b71Sopenharmony_ci@Component
969e41f4b71Sopenharmony_cistruct LocalMapSample {
970e41f4b71Sopenharmony_ci  @LocalStorageLink("map") message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]]);
971e41f4b71Sopenharmony_ci
972e41f4b71Sopenharmony_ci  build() {
973e41f4b71Sopenharmony_ci    Row() {
974e41f4b71Sopenharmony_ci      Column() {
975e41f4b71Sopenharmony_ci        ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
976e41f4b71Sopenharmony_ci          Text(`${item[0]}`).fontSize(30)
977e41f4b71Sopenharmony_ci          Text(`${item[1]}`).fontSize(30)
978e41f4b71Sopenharmony_ci          Divider()
979e41f4b71Sopenharmony_ci        })
980e41f4b71Sopenharmony_ci        Button('init map').onClick(() => {
981e41f4b71Sopenharmony_ci          this.message = new Map([[0, "a"], [1, "b"], [3, "c"]]);
982e41f4b71Sopenharmony_ci        })
983e41f4b71Sopenharmony_ci        Button('set new one').onClick(() => {
984e41f4b71Sopenharmony_ci          this.message.set(4, "d");
985e41f4b71Sopenharmony_ci        })
986e41f4b71Sopenharmony_ci        Button('clear').onClick(() => {
987e41f4b71Sopenharmony_ci          this.message.clear();
988e41f4b71Sopenharmony_ci        })
989e41f4b71Sopenharmony_ci        Button('replace the existing one').onClick(() => {
990e41f4b71Sopenharmony_ci          this.message.set(0, "aa");
991e41f4b71Sopenharmony_ci        })
992e41f4b71Sopenharmony_ci        Button('delete the existing one').onClick(() => {
993e41f4b71Sopenharmony_ci          this.message.delete(0);
994e41f4b71Sopenharmony_ci        })
995e41f4b71Sopenharmony_ci      }
996e41f4b71Sopenharmony_ci      .width('100%')
997e41f4b71Sopenharmony_ci    }
998e41f4b71Sopenharmony_ci    .height('100%')
999e41f4b71Sopenharmony_ci  }
1000e41f4b71Sopenharmony_ci}
1001e41f4b71Sopenharmony_ci```
1002e41f4b71Sopenharmony_ci
1003e41f4b71Sopenharmony_ci
1004e41f4b71Sopenharmony_ci### Decorating Variables of the Set Type
1005e41f4b71Sopenharmony_ci
1006e41f4b71Sopenharmony_ci> **NOTE**
1007e41f4b71Sopenharmony_ci>
1008e41f4b71Sopenharmony_ci> LocalStorage supports the Set type since API version 12.
1009e41f4b71Sopenharmony_ci
1010e41f4b71Sopenharmony_ciIn this example, the **memberSet** variable decorated by @LocalStorageLink is of the Set\<number\> type. After the button is clicked, the value of **memberSet** changes, and the UI is re-rendered.
1011e41f4b71Sopenharmony_ci
1012e41f4b71Sopenharmony_ci```ts
1013e41f4b71Sopenharmony_ci@Entry
1014e41f4b71Sopenharmony_ci@Component
1015e41f4b71Sopenharmony_cistruct LocalSetSample {
1016e41f4b71Sopenharmony_ci  @LocalStorageLink("set") memberSet: Set<number> = new Set([0, 1, 2, 3, 4]);
1017e41f4b71Sopenharmony_ci
1018e41f4b71Sopenharmony_ci  build() {
1019e41f4b71Sopenharmony_ci    Row() {
1020e41f4b71Sopenharmony_ci      Column() {
1021e41f4b71Sopenharmony_ci        ForEach(Array.from(this.memberSet.entries()), (item: [number, string]) => {
1022e41f4b71Sopenharmony_ci          Text(`${item[0]}`)
1023e41f4b71Sopenharmony_ci            .fontSize(30)
1024e41f4b71Sopenharmony_ci          Divider()
1025e41f4b71Sopenharmony_ci        })
1026e41f4b71Sopenharmony_ci        Button('init set')
1027e41f4b71Sopenharmony_ci          .onClick(() => {
1028e41f4b71Sopenharmony_ci            this.memberSet = new Set([0, 1, 2, 3, 4]);
1029e41f4b71Sopenharmony_ci          })
1030e41f4b71Sopenharmony_ci        Button('set new one')
1031e41f4b71Sopenharmony_ci          .onClick(() => {
1032e41f4b71Sopenharmony_ci            this.memberSet.add(5);
1033e41f4b71Sopenharmony_ci          })
1034e41f4b71Sopenharmony_ci        Button('clear')
1035e41f4b71Sopenharmony_ci          .onClick(() => {
1036e41f4b71Sopenharmony_ci            this.memberSet.clear();
1037e41f4b71Sopenharmony_ci          })
1038e41f4b71Sopenharmony_ci        Button('delete the first one')
1039e41f4b71Sopenharmony_ci          .onClick(() => {
1040e41f4b71Sopenharmony_ci            this.memberSet.delete(0);
1041e41f4b71Sopenharmony_ci          })
1042e41f4b71Sopenharmony_ci      }
1043e41f4b71Sopenharmony_ci      .width('100%')
1044e41f4b71Sopenharmony_ci    }
1045e41f4b71Sopenharmony_ci    .height('100%')
1046e41f4b71Sopenharmony_ci  }
1047e41f4b71Sopenharmony_ci}
1048e41f4b71Sopenharmony_ci```
1049e41f4b71Sopenharmony_ci
1050e41f4b71Sopenharmony_ci<!--no_check-->
1051