# LocalStorage: Storing UI State
LocalStorage 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.
This topic describes only the LocalStorage application scenarios and related decorators: \@LocalStorageProp and \@LocalStorageLink.
Before reading this topic, you are advised to read [State Management Overview](./arkts-state-management-overview.md) to have a basic understanding of the state management framework.
LocalStorage also provides APIs for you to manually add, delete, change, and query keys of Storage outside the custom component. You are advised to read this topic together with [LocalStorage API reference](../reference/apis-arkui/arkui-ts/ts-state-management.md#localstorage9).
> **NOTE**
>
> LocalStorage is supported since API version 9.
## Overview
LocalStorage is an in-memory "database" that ArkTS provides for storing state variables required to build pages of the application UI.
- 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.
- 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.
- The \@Component decorated components can automatically inherit the LocalStorage instance from the parent component or receive the specified LocalStorage instance. For details, see [Example of Providing a Custom Component with Access to a LocalStorage Instance](#example-of-providing-a-custom-component-with-access-to-a-localstorage-instance).
- All attributes in LocalStorage are mutable.
The 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.
LocalStorage provides two decorators based on the synchronization type of the component decorated with \@Component:
- [@LocalStorageProp](#localstorageprop): creates a one-way data synchronization with the named attribute in LocalStorage.
- [@LocalStorageLink](#localstoragelink): creates a two-way data synchronization with the named attribute in LocalStorage.
## \@LocalStorageProp
As 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.
When 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.)
> **NOTE**
>
> This decorator can be used in ArkTS widgets since API version 9.
>
> This decorator can be used in atomic services since API version 11.
By 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.
### Rules of Use
| \@LocalStorageProp Decorator| Description |
| ----------------------- | ---------------------------------------- |
| Decorator parameters | **key**: constant string, mandatory (the string must be quoted) |
| Allowed variable types | Object, class, string, number, Boolean, enum, and array of these types. (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). 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. **any** is not supported. **undefined** and **null** are supported since API version 12. (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). **NOTE** 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.|
| 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.|
| Initial value for the decorated variable | Mandatory. If the attribute does not exist in LocalStorage, it will be created and initialized with this value.|
### Variable Transfer/Access Rules
| Transfer/Access | Description |
| ---------- | ---------------------------------------- |
| Initialization and update from the parent component| Forbidden.|
| 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.|
| Access from outside the component | Not supported. |
**Figure 1** \@LocalStorageProp initialization rule

### Observed Changes and Behavior
**Observed Changes**
- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
- 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).
- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed.
- 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).
- 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).
- 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).
**Framework Behavior**
- Value changes of the variables decorated by \@LocalStorageProp are not synchronized to LocalStorage.
- Value changes of the variables decorated by \@LocalStorageProp will cause a re-render of components associated with the current custom component.
- 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.

## \@LocalStorageLink
> **NOTE**
>
> This decorator can be used in atomic services since API version 11.
\@LocalStorageLink is required if you need to synchronize the changes of the state variables in a custom component back to LocalStorage.
\@LocalStorageLink(key) creates a two-way data synchronization with the attribute with the given key in LocalStorage.
1. If a local change occurs, it is synchronized to LocalStorage.
2. 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).
### Rules of Use
| \@LocalStorageLink Decorator| Description |
| ----------------------- | ---------------------------------------- |
| Decorator parameters | **key**: constant string, mandatory (the string must be quoted) |
| Allowed variable types | Object, class, string, number, Boolean, enum, and array of these types. (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). 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. **any** is not supported. **undefined** and **null** are supported since API version 12. (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). **NOTE** 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.|
| Synchronization type | Two-way: from the attribute in LocalStorage to the custom component variable and back|
| Initial value for the decorated variable | Mandatory. If the attribute does not exist in LocalStorage, it will be created and initialized with this value.|
### Variable Transfer/Access Rules
| Transfer/Access | Description |
| ---------- | ---------------------------------------- |
| Initialization and update from the parent component| Forbidden.|
| 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.|
| Access from outside the component | Not supported. |
**Figure 2** \@LocalStorageLink initialization rule

### Observed Changes and Behavior
**Observed Changes**
- When the decorated variable is of the Boolean, string, or number type, its value change can be observed.
- 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).
- When the decorated variable is of the array type, the addition, deletion, and updates of array items can be observed.
- 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).
- 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).
- 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).
**Framework Behavior**
1. 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.
2. 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.
3. 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.

## Constraints
1. The parameter of \@LocalStorageProp and \@LocalStorageLink must be of the string type. Otherwise, an error is reported during compilation.
```ts
let storage = new LocalStorage();
storage.setOrCreate('PropA', 48);
// Incorrect format. An error is reported during compilation.
@LocalStorageProp() localStorageProp: number = 1;
@LocalStorageLink() localStorageLink: number = 2;
// Correct format.
@LocalStorageProp('PropA') localStorageProp: number = 1;
@LocalStorageLink('PropA') localStorageLink: number = 2;
```
2. \@StorageProp and \@StorageLink cannot decorate variables of the function type. Otherwise, the framework throws a runtime error.
3. Once created, a named attribute cannot have its type changed. Subsequent calls to **Set** must set a value of same type.
4. 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).
## Use Scenarios
### Example of Using LocalStorage in Application Logic
```ts
let para: Record = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para); // Create an instance and initialize it with the given object.
let propA: number | undefined = storage.get('PropA'); // propA == 47
let link1: SubscribedAbstractProperty = storage.link('PropA'); // link1.get() == 47
let link2: SubscribedAbstractProperty = storage.link('PropA'); // link2.get() == 47
let prop: SubscribedAbstractProperty = storage.prop('PropA'); // prop.get() == 47
link1.set(48); // Two-way synchronization: link1.get() == link2.get() == prop.get() == 48
prop.set(1); // One-way synchronization: prop.get() == 1; but link1.get() == link2.get() == 48
link1.set(49); // Two-way synchronization: link1.get() == link2.get() == prop.get() == 49
```
### Example for Using LocalStorage from Inside the UI
The two decorators \@LocalStorageProp and \@LocalStorageLink can work together to obtain the state variable stored in a LocalStorage instance in the UI component.
This example uses \@LocalStorageLink to implement the following:
- Use the **build** function to create a LocalStorage instance named **storage**.
- Use the \@Entry decorator to add **storage** to the top-level component **Parent**.
- Use \@LocalStorageLink to create a two-way data synchronization with the given attribute in LocalStorage.
```ts
class Data {
code: number;
constructor(code: number) {
this.code = code;
}
}
// Create a new instance and initialize it with the given object.
let para: Record = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para);
storage.setOrCreate('PropB', new Data(50));
@Component
struct Child {
// @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageLink('PropA') childLinkNumber: number = 1;
// @LocalStorageLink creates a two-way data synchronization with the PropB attribute in LocalStorage.
@LocalStorageLink('PropB') childLinkObject: Data = new Data(0);
build() {
Column({ space: 15 }) {
Button(`Child from LocalStorage ${this.childLinkNumber}`) // The changes will be synchronized to PropA in LocalStorage and with Parent.parentLinkNumber.
.onClick(() => {
this.childLinkNumber += 1;
})
Button(`Child from LocalStorage ${this.childLinkObject.code}`) // The changes will be synchronized to PropB in LocalStorage and with Parent.parentLinkObject.code.
.onClick(() => {
this.childLinkObject.code += 1;
})
}
}
}
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct Parent {
// @LocalStorageLink creates a two-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageLink('PropA') parentLinkNumber: number = 1;
// @LocalStorageLink creates a two-way data synchronization with the PropB attribute in LocalStorage.
@LocalStorageLink('PropB') parentLinkObject: Data = new Data(0);
build() {
Column({ space: 15 }) {
Button(`Parent from LocalStorage ${this.parentLinkNumber}`) // The value of this.parentLinkNumber is 47 because PropA in LocalStorage has been initialized.
.onClick(() => {
this.parentLinkNumber += 1;
})
Button(`Parent from LocalStorage ${this.parentLinkObject.code}`) // The value of this.parentLinkObject.code is 50 because PropB in LocalStorage has been initialized.
.onClick(() => {
this.parentLinkObject.code += 1;
})
// The @Component decorated child component automatically obtains access to the Parent LocalStorage instance.
Child()
}
}
}
```
### Simple Example of Using \@LocalStorageProp with LocalStorage
In this example, the **Parent** and **Child** components create local data that is one-way synchronized with the PropA attribute in the LocalStorage instance **storage**.
- The change of **this.storageProp1** in **Parent** takes effect only in **Parent** and is not synchronized to **storage**.
- In the **Child** component, the value of **storageProp2** bound to **Text** is still 47.
```ts
// Create a new instance and initialize it with the given object.
let para: Record = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para);
// Make LocalStorage accessible from the @Component decorated component.
@Entry(storage)
@Component
struct Parent {
// @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageProp('PropA') storageProp1: number = 1;
build() {
Column({ space: 15 }) {
// 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.
Button(`Parent from LocalStorage ${this.storageProp1}`)
.onClick(() => {
this.storageProp1 += 1;
})
Child()
}
}
}
@Component
struct Child {
// @LocalStorageProp creates a one-way data synchronization with the PropA attribute in LocalStorage.
@LocalStorageProp('PropA') storageProp2: number = 2;
build() {
Column({ space: 15 }) {
// When Parent changes, the current storageProp2 does not change, and 47 is displayed.
Text(`Parent from LocalStorage ${this.storageProp2}`)
}
}
}
```
### Simple Example of Using \@LocalStorageLink with LocalStorage
This example shows how to create a two-way data synchronization between an \@LocalStorageLink decorated variable and LocalStorage.
```ts
// Create a LocalStorage instance.
let para: Record = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para);
// Call the link API (available since API version 9) to create a two-way data synchronization with PropA. linkToPropA is a global variable.
let linkToPropA: SubscribedAbstractProperty