1# State Management with Application-level Variables 2 3This topic covers how to manage the application status with application-level variables. For details about the APIs, see [State Management with Application-level Variables](../reference/arkui-ts/ts-state-management.md). 4 5## AppStorage 6 7The [AppStorage](../reference/arkui-ts/ts-state-management.md#appstorage) is a singleton object in an application that provides central storage for changing state attributes of an application. It is created by the UI framework when the application is started and destroyed when the application exits. 8 9The **AppStorage** contains all the state attributes that need to be accessed throughout the application. It retains all attributes and their values as long as the application remains running, and the attribute values can be accessed through unique key values. 10 11Components can synchronize the application state data with the **AppStorage** through decorators. The application service logic can also be implemented by accessing the **AppStorage** through APIs. 12 13The selection state attribute of the **AppStorage** can be synchronized with different data sources or data sinks. These data sources and data sinks can be local or remote devices and provide different functions, such as data persistence. Such data sources and data sinks can be implemented independently of the UI in the service logic. 14 15By default, the attributes in the **AppStorage** are mutable. If needed, **AppStorage** can also use immutable (read-only) attributes. 16 17> **NOTE** 18> 19> [Worker](../reference/apis/js-apis-worker.md) can interact with the main thread only through [postMessage](../reference/apis/js-apis-worker.md#postmessage). 20 21### @StorageLink Decorator 22 23Two-way data binding can be established between components and the **AppStorage** through state variables decorated by **@StorageLink(*key*)**. Wherein, **key** is the attribute key value in the **AppStorage**. When a component containing the **@StorageLink** decorated variable is created, the variable is initialized using the value in the **AppStorage**. Changes made to this variable in the component will be first synchronized to the **AppStorage**, and then to other bound instances, such as **PersistentStorage** or other bound UI components. 24 25### @StorageProp Decorator 26 27One-way data binding can be established between components and the **AppStorage** through state variables decorated by **@StorageProp(*key*)**. Wherein, **key** is the attribute key value in the **AppStorage**. When a component containing the **@StorageProp** decorated variable is created, the variable is initialized using the value in the **AppStorage**. Changes made to the value in the **AppStorage** will cause the bound UI component to update the state. 28 29### Example 30 31Each time the user clicks the **Count** button, the value of **this.varA** will increase by 1. This variable is synchronized with **varA** in the **AppStorage**. Each time the user clicks the language button, the value of **languageCode** in the **AppStorage** will be changed, and the change is synchronized to the **this.languageCode** variable. 32 33```ts 34// xxx.ets 35@Entry 36@Component 37struct ComponentA { 38 @StorageLink('varA') varA: number = 2 39 @StorageProp('languageCode') languageCode: string = 'en' 40 private label: string = 'count' 41 42 aboutToAppear() { 43 this.label = (this.languageCode === 'en') ? 'Number' : 'Count' 44 } 45 46 build() { 47 Column() { 48 Row({ space: 20 }) { 49 Button(`${this.label}: ${this.varA}`) 50 .onClick(() => { 51 AppStorage.Set<number>('varA', AppStorage.Get<number>('varA') + 1) 52 }) 53 Button(`language: ${this.languageCode}`) 54 .onClick(() => { 55 if (AppStorage.Get<string>('languageCode') === 'zh') { 56 AppStorage.Set<string>('languageCode', 'en') 57 } else { 58 AppStorage.Set<string>('languageCode', 'zh') 59 } 60 this.label = (this.languageCode === 'en') ? 'Number' : 'Count' 61 }) 62 } 63 .margin({ top: 50, bottom: 50 }) 64 65 Row() { 66 Button (`Change @StorageLink decorated variable: ${this.varA}`).height(40).fontSize(14) 67 .onClick(() => { 68 this.varA++ 69 }) 70 } 71 }.width('100%') 72 } 73} 74``` 75 76 77 78## LocalStorage 79 80> **NOTE** 81> 82> This API is supported since API version 9. Updates will be marked with a superscript to indicate their earliest API version. 83 84The **LocalStorage** is a storage unit in an application. Its lifecycle follows its associated ability. In the stage model, the **LocalStorage** provides global data isolation between abilities and applies to where a data sharing scope smaller than that provided by the **AppStorage** is required. The **LocalStorage** also provides storage for application-wide mutable and immutable state attributes, which are used for building part of the application UI, such as an ability UI. The **LocalStorage** resolves the data interference between the application and the abilities and, in multi-instance scenarios, data interference between different **Ability** instances under the same **Ability** class. In distributed migration scenarios, **Ability**, as the minimum unit for the system to schedule applications, allows for easier component data migration when working with the **LocalStorage**. 85 86At the application layer, multiple **LocalStorage** instances can be created for an application, each corresponding to an ability of the application. 87 88An application can have multiple abilities. At most one **LocalStorage** instance can be allocated to the components in an ability. In addition, all components in the ability inherit access to the objects stored in the **LocalStorage** instance. 89 90A component can access a maximum of one **LocalStorage** instance, and one **LocalStorage** instance can be assigned to multiple components. 91 92### @LocalStorageLink Decorator 93 94Two-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageLink(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageLink** decorated state variable is created, the state variable is initialized with the initial value in the **LocalStorage**. If no initial value is assigned in the **LocalStorage**, the state variable will use the value defined by **@LocalStorageLink**. Changes made to the **@LocalStorageLink** decorated variable in a component will be first synchronized to the **LocalStorage**, and then to other bound UI components under the same ability. 95 96### @LocalStorageProp Decorator 97 98One-way data binding can be established between a component and the **LocalStorage** through the component's state variable decorated by **@LocalStorageProp(*key*)**. Wherein, **key** is the attribute key value in the **LocalStorage**. When a component that contains a **@LocalStorageProp** decorated state variable is created, the state variable is initialized with the initial value in the **LocalStorage**. Changes made to the value in the **LocalStorage** will cause all UI components under the current ability to update the state. 99 100> **NOTE** 101> 102> If a **LocalStorage** instance does not have an initial value assigned when being created, it can use the initial value defined by **@LocalStorageLink** or **@LocalStorageProp** in the component. 103 104### Example 1: Creating a LocalStorage Instance in an Ability 105 106The **LocalStorage** is loaded through the **loadContent** API. For details, see [loadContent](../reference/apis/js-apis-window.md#loadcontent9-1). 107 108```ts 109// MainAbility.ts 110import Ability from '@ohos.application.Ability' 111 112export default class MainAbility extends Ability { 113 storage: LocalStorage 114 115 onCreate() { 116 this.storage = new LocalStorage() 117 this.storage.setOrCreate('storageSimpleProp', 121) 118 console.info('[Demo MainAbility onCreate]') 119 } 120 121 onDestroy() { 122 console.info('[Demo MainAbility onDestroy]') 123 } 124 125 onWindowStageCreate(windowStage) { 126 // storage is passed to the loadContent API as a parameter. 127 windowStage.loadContent('pages/Index', this.storage) 128 } 129 130 onWindowStageDestroy() { 131 console.info('[Demo] MainAbility onWindowStageDestroy') 132 } 133 134 onForeground() { 135 console.info('[Demo] MainAbility onForeground') 136 } 137 138 onBackground() { 139 console.info('[Demo] MainAbility onBackground') 140 } 141} 142``` 143 144The **@Component** decorated component obtains data. 145 146```ts 147// Index.ets 148let storage = LocalStorage.GetShared() 149 150@Entry(storage) 151@Component 152struct LocalStorageComponent { 153 @LocalStorageLink('storageSimpleProp') simpleVarName: number = 0 154 155 build() { 156 Column() { 157 Button(`LocalStorageLink: ${this.simpleVarName.toString()}`) 158 .margin(20) 159 .onClick(() => { 160 this.simpleVarName += 1 161 }) 162 Text(JSON.stringify(this.simpleVarName)) 163 .fontSize(50) 164 LocalStorageComponentProp() 165 }.width('100%') 166 } 167} 168 169@Component 170struct LocalStorageComponentProp { 171 @LocalStorageProp('storageSimpleProp') simpleVarName: number = 0 172 173 build() { 174 Column() { 175 Button(`LocalStorageProp: ${this.simpleVarName.toString()}`) 176 .margin(20) 177 .onClick(() => { 178 this.simpleVarName += 1 179 }) 180 Text(JSON.stringify(this.simpleVarName)) 181 .fontSize(50) 182 }.width('100%') 183 } 184} 185``` 186 187 188 189### Example 2: Defining LocalStorage on the Entry Page 190 191```ts 192// xxx.ets 193let storage = new LocalStorage({ "PropA": 47 }) 194 195@Entry(storage) 196@Component 197struct ComA { 198 @LocalStorageLink("PropA") storageLink: number = 1 199 200 build() { 201 Column() { 202 Text(`Parent from LocalStorage ${this.storageLink}`) 203 .fontSize(18) 204 .margin(20) 205 .onClick(() => this.storageLink += 1) 206 Child() 207 } 208 } 209} 210 211@Component 212struct Child { 213 @LocalStorageLink("PropA") storageLink: number = 1 214 215 build() { 216 Text(`Child from LocalStorage ${this.storageLink}`) 217 .fontSize(18) 218 .margin(20) 219 .onClick(() => this.storageLink += 1) 220 } 221} 222``` 223 224 225 226## PersistentStorage 227 228[PersistentStorage](../reference/arkui-ts/ts-state-management.md#persistentstorage) provides a set of static methods for managing persistent data of applications. Persistent data with specific tags can be linked to the **AppStorage**, and then the persistent data can be accessed through the **AppStorage** APIs. Alternatively, the **@StorageLink** decorator can be used to access the variable that matches the specific key. 229 230> **NOTE** 231> 232> - When using the **PersistProp** API in **PersistentStorage**, ensure that the input key exists in the **AppStorage**. 233> - The **DeleteProp** API in **PersistentStorage** takes effect only for the data that has been linked during the current application startup. 234 235```ts 236// xxx.ets 237PersistentStorage.PersistProp('highScore', '0') 238 239@Entry 240@Component 241struct PersistentComponent { 242 @StorageLink('highScore') highScore: string = '0' 243 @State currentScore: number = 0 244 245 build() { 246 Column() { 247 if (this.currentScore === Number(this.highScore)) { 248 Text(`new highScore : ${this.highScore}`).fontSize(18) 249 } 250 Button(`goal!, currentScore : ${this.currentScore}`) 251 .margin(20) 252 .onClick(() => { 253 this.currentScore++ 254 if (this.currentScore > Number(this.highScore)) { 255 this.highScore = this.currentScore.toString() 256 } 257 }) 258 }.width('100%') 259 } 260} 261``` 262 263 264 265## Environment 266 267[Environment](../reference/arkui-ts/ts-state-management.md#environment) is a singleton object created by the framework when the application is started. It provides the **AppStorage** with an array of environment state attributes required by the application. These attributes, such as the system language and color mode, describe the device environment where the application runs. **Environment** and its attributes are immutable, and all attribute values are of simple types. The following example shows how to obtain whether accessibility is enabled from **Environment**: 268 269```ts 270Environment.EnvProp('accessibilityEnabled', 'default') 271var enable = AppStorage.Get('accessibilityEnabled') 272``` 273 274**accessibilityEnabled** is the default system variable identifier provided by **Environment**. You need to bind the corresponding system attribute to the **AppStorage**. Then, you can use the methods or decorators in the **AppStorage** to access the corresponding system attribute data. 275