1e41f4b71Sopenharmony_ci# ArkUI Subsystem Changelog 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## cl.arkui.1 Verification Against Undefined Keys for Decorators 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci**Access Level** 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciPublic 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci**Reason for Change** 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ciThe **key** value should be verified for all decorators to comply with TypeScript syntax rules. 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ciThe following decorators are involved: 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci@LocalStorageLink, @LocalStorageProp, @StorageProp, @StorageLink, @Provide, @Consume, @Watch 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ci**Change Impact** 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ciIf the **key** value of any of the aforementioned decorators is not defined, a compilation error is reported. 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ciThis change is a non-compatible change. 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci**Start API Level** 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci@LocalStorageLink: API version 9 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci@LocalStorageProp: API version 9 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci@StorageProp: API version 7 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci@StorageLink: API version 7 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci@Provide: API version 7 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ci@Consume: API version 7 36e41f4b71Sopenharmony_ci 37e41f4b71Sopenharmony_ci@Watch: API version 7 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci 41e41f4b71Sopenharmony_ci**Change Since** 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ciOpenHarmony SDK 5.0.0.13 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ciExample: 46e41f4b71Sopenharmony_ci 47e41f4b71Sopenharmony_ci``` 48e41f4b71Sopenharmony_ci@Entry 49e41f4b71Sopenharmony_ci@Component 50e41f4b71Sopenharmony_cistruct ComA { 51e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 52e41f4b71Sopenharmony_ci @StorageProp(aaa) storageProp: string = 'storageProp'; 53e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 54e41f4b71Sopenharmony_ci @StorageLink(aaa) storageLink: string = 'storageLink'; 55e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 56e41f4b71Sopenharmony_ci @LocalStorageLink(aaa) localStorageLink: string = 'localStorageLink'; 57e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 58e41f4b71Sopenharmony_ci @LocalStorageProp(aaa) localStorageProp: string = 'localStorageProp'; 59e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 60e41f4b71Sopenharmony_ci @Provide(aaa) provide: string = 'provide'; 61e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 62e41f4b71Sopenharmony_ci @Consume(aaa) consume: number; 63e41f4b71Sopenharmony_ci // ERROR: Cannot find name 'aaa'. 64e41f4b71Sopenharmony_ci @State @Watch(aaa) watch: number = 0; 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci build() { 67e41f4b71Sopenharmony_ci } 68e41f4b71Sopenharmony_ci} 69e41f4b71Sopenharmony_ci 70e41f4b71Sopenharmony_ci``` 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ci**Adaptation Guide** 73e41f4b71Sopenharmony_ci 74e41f4b71Sopenharmony_ci Make sure the **key** value for the following decorators is defined: @LocalStorageLink, @LocalStorageProp, @StorageProp, @StorageLink, @Provide, @Consume, and @Watch. 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci``` 77e41f4b71Sopenharmony_ci// test.ts 78e41f4b71Sopenharmony_ciexport let oneKey = 'string'; 79e41f4b71Sopenharmony_ci``` 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ci 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci``` 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci// index.ets 86e41f4b71Sopenharmony_ciimport { oneKey } from './test'; 87e41f4b71Sopenharmony_ci@Entry 88e41f4b71Sopenharmony_ci@Component 89e41f4b71Sopenharmony_cistruct ComA { 90e41f4b71Sopenharmony_ci @StorageProp(oneKey) storageProp: string = 'storageProp'; 91e41f4b71Sopenharmony_ci @StorageLink(oneKey) storageLink: string = 'storageLink'; 92e41f4b71Sopenharmony_ci @LocalStorageLink(oneKey) localStorageLink: string = 'localStorageLink'; 93e41f4b71Sopenharmony_ci @LocalStorageProp(oneKey) localStorageProp: string = 'localStorageProp'; 94e41f4b71Sopenharmony_ci @Provide(oneKey) provide: string = 'provide'; 95e41f4b71Sopenharmony_ci @Consume(oneKey) consume: number; 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci build() { 98e41f4b71Sopenharmony_ci } 99e41f4b71Sopenharmony_ci} 100e41f4b71Sopenharmony_ci``` 101e41f4b71Sopenharmony_ci 102e41f4b71Sopenharmony_ci 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci## cl.arkui.2 Addition of undefined and null Support for AppStorage, LocalStorage, and PersistentStorage 106e41f4b71Sopenharmony_ci 107e41f4b71Sopenharmony_ci**Access Level** 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ciPublic 110e41f4b71Sopenharmony_ci 111e41f4b71Sopenharmony_ci**Change Impact** 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ciThe AppStorage, LocalStorage, and PersistentStorage APIs now accept **null** and **undefined** as input parameters. The @StorageLink, @StorageProp, @LocalStorageLink, and @LocalStorageProp decorators now support **null** and **undefined** types. 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ciTake @StorageLink as an example. If an AppStorage API uses **null** or **undefined** as the initial or target value, then: In the semantics before change, calling the API reports a warning and does not take effect. In the semantics after change, **null** or **undefined** is saved as the initial or target value in AppStorage. This change causes the original application code to crash in the following scenario: 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ciBefore change: 118e41f4b71Sopenharmony_ci 119e41f4b71Sopenharmony_ci```ts 120e41f4b71Sopenharmony_ciclass PropA { 121e41f4b71Sopenharmony_ci num: number = 100; 122e41f4b71Sopenharmony_ci} 123e41f4b71Sopenharmony_ci 124e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null); 125e41f4b71Sopenharmony_ciAppStorage.has("PropA");// Because null and undefined are not supported, false is returned. 126e41f4b71Sopenharmony_ci 127e41f4b71Sopenharmony_ci@Entry 128e41f4b71Sopenharmony_ci@Component 129e41f4b71Sopenharmony_cistruct TestPage { 130e41f4b71Sopenharmony_ci @StorageLink('PropA') propA: PropA = new PropA(); 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci build() { 133e41f4b71Sopenharmony_ci Column() { 134e41f4b71Sopenharmony_ci Text(this.propA.num.toString()) // propA is locally initialized to 100. 135e41f4b71Sopenharmony_ci } 136e41f4b71Sopenharmony_ci } 137e41f4b71Sopenharmony_ci} 138e41f4b71Sopenharmony_ci``` 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ciAfter change: 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci```ts 143e41f4b71Sopenharmony_ciclass PropA { 144e41f4b71Sopenharmony_ci num: number = 100; 145e41f4b71Sopenharmony_ci} 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null); 148e41f4b71Sopenharmony_ciAppStorage.has("PropA");// Because null and undefined are supported, true is returned. 149e41f4b71Sopenharmony_ci 150e41f4b71Sopenharmony_ci@Entry 151e41f4b71Sopenharmony_ci@Component 152e41f4b71Sopenharmony_cistruct TestPage { 153e41f4b71Sopenharmony_ci @StorageLink('PropA') propA: PropA = new PropA(); 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ci build() { 156e41f4b71Sopenharmony_ci Column() { 157e41f4b71Sopenharmony_ci Text(this.propA.num.toString()) // propA is initialized with the value null in AppStorage. As a result, JsCrash is triggered during invoking. 158e41f4b71Sopenharmony_ci } 159e41f4b71Sopenharmony_ci } 160e41f4b71Sopenharmony_ci} 161e41f4b71Sopenharmony_ci``` 162e41f4b71Sopenharmony_ci 163e41f4b71Sopenharmony_ci**Key API/Component Changes** 164e41f4b71Sopenharmony_ci 165e41f4b71Sopenharmony_ciAppStorage: **set**, **setOrCreate**, **setAndLink**, **setAndProp** 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ciLocalStorage: **set**, **setOrCreate**, **setAndLink**, **setAndProp** 168e41f4b71Sopenharmony_ci 169e41f4b71Sopenharmony_ciPersistentStorage: **persistProp** 170e41f4b71Sopenharmony_ci 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci**Start API Level** 173e41f4b71Sopenharmony_ci 174e41f4b71Sopenharmony_ciThis change takes effect since API version 12. 175e41f4b71Sopenharmony_ci 176e41f4b71Sopenharmony_ciAppStorage 177e41f4b71Sopenharmony_ci 178e41f4b71Sopenharmony_ci**set**: API version 10 179e41f4b71Sopenharmony_ci 180e41f4b71Sopenharmony_ci**setOrCreate**: API version 10 181e41f4b71Sopenharmony_ci 182e41f4b71Sopenharmony_ci**setAndLink**: API version 10 183e41f4b71Sopenharmony_ci 184e41f4b71Sopenharmony_ci**setAndProp**: API version 10 185e41f4b71Sopenharmony_ci 186e41f4b71Sopenharmony_ciLocalStorage 187e41f4b71Sopenharmony_ci 188e41f4b71Sopenharmony_ci**set**: API version 9 189e41f4b71Sopenharmony_ci 190e41f4b71Sopenharmony_ci**setOrCreate**: API version 9 191e41f4b71Sopenharmony_ci 192e41f4b71Sopenharmony_ci**setAndLink**: API version 9 193e41f4b71Sopenharmony_ci 194e41f4b71Sopenharmony_ci**setAndProp**: API version 9 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ciPersistentStorage 197e41f4b71Sopenharmony_ci 198e41f4b71Sopenharmony_ci**persistProp**: API version 10 199e41f4b71Sopenharmony_ci 200e41f4b71Sopenharmony_ci**Change Since** 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ciOpenHarmony SDK 5.0.0.13 203e41f4b71Sopenharmony_ci 204e41f4b71Sopenharmony_ci**Adaptation Guide** 205e41f4b71Sopenharmony_ci 206e41f4b71Sopenharmony_ci1. Do not use **null** or **undefined** to initialize variables. Use meaningful values instead. 207e41f4b71Sopenharmony_ci 208e41f4b71Sopenharmony_ci2. Changing a value to **null** or **undefined** will trigger UI re-render. 209e41f4b71Sopenharmony_ci 210e41f4b71Sopenharmony_ci3. Add a null check to the invoking position. 211e41f4b71Sopenharmony_ci 212e41f4b71Sopenharmony_ci```ts 213e41f4b71Sopenharmony_ciclass PropA { 214e41f4b71Sopenharmony_ci num: number = 100; 215e41f4b71Sopenharmony_ci} 216e41f4b71Sopenharmony_ci 217e41f4b71Sopenharmony_ciAppStorage.setOrCreate("PropA", null); 218e41f4b71Sopenharmony_ciAppStorage.has("PropA"); // Because null and undefined are supported, true is returned. 219e41f4b71Sopenharmony_ci 220e41f4b71Sopenharmony_ci@Entry 221e41f4b71Sopenharmony_ci@Component 222e41f4b71Sopenharmony_cistruct TestPage { 223e41f4b71Sopenharmony_ci @StorageLink('PropA') propA: PropA | null | undefined = new PropA(); 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci build() { 226e41f4b71Sopenharmony_ci Column() { 227e41f4b71Sopenharmony_ci Text(this.propA?.num.toString())// Check whether the value is null to prevent crashes caused by null and undefined during invoking. 228e41f4b71Sopenharmony_ci .fontSize(20) 229e41f4b71Sopenharmony_ci Button("Set propA to null") 230e41f4b71Sopenharmony_ci .margin(10) 231e41f4b71Sopenharmony_ci .onClick(() => { 232e41f4b71Sopenharmony_ci this.propA = null; 233e41f4b71Sopenharmony_ci }) 234e41f4b71Sopenharmony_ci Button("Set propA to undefined") 235e41f4b71Sopenharmony_ci .margin(10) 236e41f4b71Sopenharmony_ci .onClick(() => { 237e41f4b71Sopenharmony_ci this.propA = undefined; 238e41f4b71Sopenharmony_ci }) 239e41f4b71Sopenharmony_ci Button("Assign new PropA") 240e41f4b71Sopenharmony_ci .margin(10) 241e41f4b71Sopenharmony_ci .onClick(() => { 242e41f4b71Sopenharmony_ci this.propA = new PropA(); 243e41f4b71Sopenharmony_ci }) 244e41f4b71Sopenharmony_ci } 245e41f4b71Sopenharmony_ci } 246e41f4b71Sopenharmony_ci} 247e41f4b71Sopenharmony_ci``` 248