1e41f4b71Sopenharmony_ci# LazyForEach: Lazy Data Loading 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciFor details about API parameters, see [LazyForEach](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/apis-arkui/arkui-ts/ts-rendering-control-lazyforeach.md) APIs. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci**LazyForEach** iterates over provided data sources and creates corresponding components during each iteration. When **LazyForEach** is used in a scrolling container, the framework creates components as required within the visible area of the scrolling container. When a component is out of the visible area, the framework destroys and reclaims the component to reduce memory usage. 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci## Constraints 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci- **LazyForEach** must be used in a container component. Only the [List](../reference/apis-arkui/arkui-ts/ts-container-list.md), [Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md), [Swiper](../reference/apis-arkui/arkui-ts/ts-container-swiper.md), and [WaterFlow](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md) components support lazy loading (that is, only the visible part and a small amount of data before and after the visible part are loaded for caching). For other components, all data is loaded at once. 10e41f4b71Sopenharmony_ci- In each iteration, only one child component must be created for **LazyForEach**. That is, the child component generation function of **LazyForEach** has only one root component. 11e41f4b71Sopenharmony_ci- The generated child components must be allowed in the parent container component of **LazyForEach**. 12e41f4b71Sopenharmony_ci- **LazyForEach** can be included in an **if/else** statement, and can also contain such a statement. 13e41f4b71Sopenharmony_ci- The ID generation function must generate a unique value for each piece of data. Rendering issues will arise with components assigned duplicate IDs. 14e41f4b71Sopenharmony_ci- **LazyForEach** must use the **DataChangeListener** object to re-render UI. If the first parameter **dataSource** is re-assigned a value, an exception occurs. When **dataSource** uses a state variable, the change of the state variable does not trigger the UI re-renders performed by **LazyForEach**. 15e41f4b71Sopenharmony_ci- For better rendering performance, when the **onDataChange** API of the **DataChangeListener** object is used to update the UI, an ID different from the original one needs to be generated to trigger component re-rendering. 16e41f4b71Sopenharmony_ci- **LazyForEach** must be used with the [@Reusable](https://developer.huawei.com/consumer/en/doc/best-practices-V5/bpta-component-reuse-V5#section5601835174020) decorator to trigger node reuse. Use @Reusable to decorate the components on the **LazyForEach** list. For details, see [Reuse Rules](https://developer.huawei.com/consumer/en/doc/best-practices-V5/bpta-component-reuse-V5#section5923195311402). 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ci## Key Generation Rules 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ciDuring **LazyForEach** rendering, the system generates a unique, persistent key for each item to identify the owing component. When the key changes, the ArkUI framework considers that the array element has been replaced or modified and creates a new component based on the new key. 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci**LazyForEach** provides a parameter named **keyGenerator**, which is in effect a function through which you can customize key generation rules. If no **keyGenerator** function is defined, the ArkUI framework uses the default key generation function, that is, **(item: Object, index: number) => { return viewId + '-' + index.toString(); }**, wherein **viewId** is generated during compiler conversion. The **viewId** values in the same **LazyForEach** component are the same. 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci## Component Creation Rules 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ciAfter the key generation rules are determined, the **itemGenerator** function – the second parameter in **LazyForEach** – creates a component for each array item of the data source based on the rules. There are two cases for creating a component: [initial render](#initial-render) and [non initial render](#non-initial-render). 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci### Initial Render 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ci- ### Generating Different Key Values 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ciWhen used for initial render, **LazyForEach** generates a unique key for each array item of the data source based on the key generation rules, and creates a component. 33e41f4b71Sopenharmony_ci 34e41f4b71Sopenharmony_ci```ts 35e41f4b71Sopenharmony_ci// Basic implementation of IDataSource to handle data listener 36e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 37e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 38e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci public totalCount(): number { 41e41f4b71Sopenharmony_ci return 0; 42e41f4b71Sopenharmony_ci } 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci public getData(index: number): string { 45e41f4b71Sopenharmony_ci return this.originDataArray[index]; 46e41f4b71Sopenharmony_ci } 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci // This method is called by the framework to add a listener to the LazyForEach data source. 49e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 50e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 51e41f4b71Sopenharmony_ci console.info('add listener'); 52e41f4b71Sopenharmony_ci this.listeners.push(listener); 53e41f4b71Sopenharmony_ci } 54e41f4b71Sopenharmony_ci } 55e41f4b71Sopenharmony_ci 56e41f4b71Sopenharmony_ci // This method is called by the framework to remove the listener from the LazyForEach data source. 57e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 58e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 59e41f4b71Sopenharmony_ci if (pos >= 0) { 60e41f4b71Sopenharmony_ci console.info('remove listener'); 61e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 62e41f4b71Sopenharmony_ci } 63e41f4b71Sopenharmony_ci } 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ci // Notify LazyForEach that all child components need to be reloaded. 66e41f4b71Sopenharmony_ci notifyDataReload(): void { 67e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 68e41f4b71Sopenharmony_ci listener.onDataReloaded(); 69e41f4b71Sopenharmony_ci }) 70e41f4b71Sopenharmony_ci } 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ci // Notify LazyForEach that a child component needs to be added for the data item with the specified index. 73e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 74e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 75e41f4b71Sopenharmony_ci listener.onDataAdd(index); 76e41f4b71Sopenharmony_ci }) 77e41f4b71Sopenharmony_ci } 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci // Notify LazyForEach that the data item with the specified index has changed and the child component needs to be rebuilt. 80e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 81e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 82e41f4b71Sopenharmony_ci listener.onDataChange(index); 83e41f4b71Sopenharmony_ci }) 84e41f4b71Sopenharmony_ci } 85e41f4b71Sopenharmony_ci 86e41f4b71Sopenharmony_ci // Notify LazyForEach that the child component needs to be deleted from the data item with the specified index. 87e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 88e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 89e41f4b71Sopenharmony_ci listener.onDataDelete(index); 90e41f4b71Sopenharmony_ci }) 91e41f4b71Sopenharmony_ci } 92e41f4b71Sopenharmony_ci 93e41f4b71Sopenharmony_ci // Notify LazyForEach that data needs to be swapped between the from and to positions. 94e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 95e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 96e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 97e41f4b71Sopenharmony_ci }) 98e41f4b71Sopenharmony_ci } 99e41f4b71Sopenharmony_ci} 100e41f4b71Sopenharmony_ci 101e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 102e41f4b71Sopenharmony_ci private dataArray: string[] = []; 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci public totalCount(): number { 105e41f4b71Sopenharmony_ci return this.dataArray.length; 106e41f4b71Sopenharmony_ci } 107e41f4b71Sopenharmony_ci 108e41f4b71Sopenharmony_ci public getData(index: number): string { 109e41f4b71Sopenharmony_ci return this.dataArray[index]; 110e41f4b71Sopenharmony_ci } 111e41f4b71Sopenharmony_ci 112e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 113e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 114e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 115e41f4b71Sopenharmony_ci } 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci public pushData(data: string): void { 118e41f4b71Sopenharmony_ci this.dataArray.push(data); 119e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 120e41f4b71Sopenharmony_ci } 121e41f4b71Sopenharmony_ci} 122e41f4b71Sopenharmony_ci 123e41f4b71Sopenharmony_ci@Entry 124e41f4b71Sopenharmony_ci@Component 125e41f4b71Sopenharmony_cistruct MyComponent { 126e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 127e41f4b71Sopenharmony_ci 128e41f4b71Sopenharmony_ci aboutToAppear() { 129e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 130e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 131e41f4b71Sopenharmony_ci } 132e41f4b71Sopenharmony_ci } 133e41f4b71Sopenharmony_ci 134e41f4b71Sopenharmony_ci build() { 135e41f4b71Sopenharmony_ci List({ space: 3 }) { 136e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 137e41f4b71Sopenharmony_ci ListItem() { 138e41f4b71Sopenharmony_ci Row() { 139e41f4b71Sopenharmony_ci Text(item).fontSize(50) 140e41f4b71Sopenharmony_ci .onAppear(() => { 141e41f4b71Sopenharmony_ci console.info("appear:" + item) 142e41f4b71Sopenharmony_ci }) 143e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 144e41f4b71Sopenharmony_ci } 145e41f4b71Sopenharmony_ci }, (item: string) => item) 146e41f4b71Sopenharmony_ci }.cachedCount(5) 147e41f4b71Sopenharmony_ci } 148e41f4b71Sopenharmony_ci} 149e41f4b71Sopenharmony_ci``` 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ciIn the preceding code snippets, the key generation rule is the return value **item** of the **keyGenerator** function. During loop rendering, **LazyForEach** generates keys in the sequence of **Hello 0**, **Hello 1**, ..., **Hello 20** for the array item of the data source, creates the corresponding **ListItem** child components and render them on the GUI. 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ciThe figure below shows the effect. 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ci**Figure 1** Initial render of LazyForEach 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci- ### Incorrect Rendering When Keys Are the Same 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ciWhen the keys generated for different data items are the same, the behavior of the framework is unpredictable. For example, in the following code, the keys of the data items rendered by **LazyForEach** are the same. During the swipe process, **LazyForEach** preloads child components for the current page. Because the new child component and the destroyed component have the same key, the framework may incorrectly obtain the cache. As a result, the child component rendering is abnormal. 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci ```ts 163e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 164e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 165e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 166e41f4b71Sopenharmony_ci 167e41f4b71Sopenharmony_ci public totalCount(): number { 168e41f4b71Sopenharmony_ci return 0; 169e41f4b71Sopenharmony_ci } 170e41f4b71Sopenharmony_ci 171e41f4b71Sopenharmony_ci public getData(index: number): string { 172e41f4b71Sopenharmony_ci return this.originDataArray[index]; 173e41f4b71Sopenharmony_ci } 174e41f4b71Sopenharmony_ci 175e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 176e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 177e41f4b71Sopenharmony_ci console.info('add listener'); 178e41f4b71Sopenharmony_ci this.listeners.push(listener); 179e41f4b71Sopenharmony_ci } 180e41f4b71Sopenharmony_ci } 181e41f4b71Sopenharmony_ci 182e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 183e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 184e41f4b71Sopenharmony_ci if (pos >= 0) { 185e41f4b71Sopenharmony_ci console.info('remove listener'); 186e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 187e41f4b71Sopenharmony_ci } 188e41f4b71Sopenharmony_ci } 189e41f4b71Sopenharmony_ci 190e41f4b71Sopenharmony_ci notifyDataReload(): void { 191e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 192e41f4b71Sopenharmony_ci listener.onDataReloaded(); 193e41f4b71Sopenharmony_ci }) 194e41f4b71Sopenharmony_ci } 195e41f4b71Sopenharmony_ci 196e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 197e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 198e41f4b71Sopenharmony_ci listener.onDataAdd(index); 199e41f4b71Sopenharmony_ci }) 200e41f4b71Sopenharmony_ci } 201e41f4b71Sopenharmony_ci 202e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 203e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 204e41f4b71Sopenharmony_ci listener.onDataChange(index); 205e41f4b71Sopenharmony_ci }) 206e41f4b71Sopenharmony_ci } 207e41f4b71Sopenharmony_ci 208e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 209e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 210e41f4b71Sopenharmony_ci listener.onDataDelete(index); 211e41f4b71Sopenharmony_ci }) 212e41f4b71Sopenharmony_ci } 213e41f4b71Sopenharmony_ci 214e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 215e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 216e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 217e41f4b71Sopenharmony_ci }) 218e41f4b71Sopenharmony_ci } 219e41f4b71Sopenharmony_ci} 220e41f4b71Sopenharmony_ci 221e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 222e41f4b71Sopenharmony_ci private dataArray: string[] = []; 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci public totalCount(): number { 225e41f4b71Sopenharmony_ci return this.dataArray.length; 226e41f4b71Sopenharmony_ci } 227e41f4b71Sopenharmony_ci 228e41f4b71Sopenharmony_ci public getData(index: number): string { 229e41f4b71Sopenharmony_ci return this.dataArray[index]; 230e41f4b71Sopenharmony_ci } 231e41f4b71Sopenharmony_ci 232e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 233e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 234e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 235e41f4b71Sopenharmony_ci } 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_ci public pushData(data: string): void { 238e41f4b71Sopenharmony_ci this.dataArray.push(data); 239e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 240e41f4b71Sopenharmony_ci } 241e41f4b71Sopenharmony_ci} 242e41f4b71Sopenharmony_ci 243e41f4b71Sopenharmony_ci@Entry 244e41f4b71Sopenharmony_ci@Component 245e41f4b71Sopenharmony_cistruct MyComponent { 246e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 247e41f4b71Sopenharmony_ci 248e41f4b71Sopenharmony_ci aboutToAppear() { 249e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 250e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 251e41f4b71Sopenharmony_ci } 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci build() { 255e41f4b71Sopenharmony_ci List({ space: 3 }) { 256e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 257e41f4b71Sopenharmony_ci ListItem() { 258e41f4b71Sopenharmony_ci Row() { 259e41f4b71Sopenharmony_ci Text(item).fontSize(50) 260e41f4b71Sopenharmony_ci .onAppear(() => { 261e41f4b71Sopenharmony_ci console.info("appear:" + item) 262e41f4b71Sopenharmony_ci }) 263e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 264e41f4b71Sopenharmony_ci } 265e41f4b71Sopenharmony_ci }, (item: string) => 'same key') 266e41f4b71Sopenharmony_ci }.cachedCount(5) 267e41f4b71Sopenharmony_ci } 268e41f4b71Sopenharmony_ci} 269e41f4b71Sopenharmony_ci ``` 270e41f4b71Sopenharmony_ci 271e41f4b71Sopenharmony_ciThe figure below shows the effect. 272e41f4b71Sopenharmony_ci 273e41f4b71Sopenharmony_ci**Figure 2** LazyForEach rendering when keys are the same 274e41f4b71Sopenharmony_ci 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci### Non Initial Render 277e41f4b71Sopenharmony_ci 278e41f4b71Sopenharmony_ciWhen the **LazyForEach** data source changes and a re-render is required, call a listener API based on the data source change to notify **LazyForEach**. Below are some use cases. 279e41f4b71Sopenharmony_ci 280e41f4b71Sopenharmony_ci- ### Adding Data 281e41f4b71Sopenharmony_ci 282e41f4b71Sopenharmony_ci```ts 283e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 284e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 285e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 286e41f4b71Sopenharmony_ci 287e41f4b71Sopenharmony_ci public totalCount(): number { 288e41f4b71Sopenharmony_ci return 0; 289e41f4b71Sopenharmony_ci } 290e41f4b71Sopenharmony_ci 291e41f4b71Sopenharmony_ci public getData(index: number): string { 292e41f4b71Sopenharmony_ci return this.originDataArray[index]; 293e41f4b71Sopenharmony_ci } 294e41f4b71Sopenharmony_ci 295e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 296e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 297e41f4b71Sopenharmony_ci console.info('add listener'); 298e41f4b71Sopenharmony_ci this.listeners.push(listener); 299e41f4b71Sopenharmony_ci } 300e41f4b71Sopenharmony_ci } 301e41f4b71Sopenharmony_ci 302e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 303e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 304e41f4b71Sopenharmony_ci if (pos >= 0) { 305e41f4b71Sopenharmony_ci console.info('remove listener'); 306e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 307e41f4b71Sopenharmony_ci } 308e41f4b71Sopenharmony_ci } 309e41f4b71Sopenharmony_ci 310e41f4b71Sopenharmony_ci notifyDataReload(): void { 311e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 312e41f4b71Sopenharmony_ci listener.onDataReloaded(); 313e41f4b71Sopenharmony_ci }) 314e41f4b71Sopenharmony_ci } 315e41f4b71Sopenharmony_ci 316e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 317e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 318e41f4b71Sopenharmony_ci listener.onDataAdd(index); 319e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]); 320e41f4b71Sopenharmony_ci }) 321e41f4b71Sopenharmony_ci } 322e41f4b71Sopenharmony_ci 323e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 324e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 325e41f4b71Sopenharmony_ci listener.onDataChange(index); 326e41f4b71Sopenharmony_ci }) 327e41f4b71Sopenharmony_ci } 328e41f4b71Sopenharmony_ci 329e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 330e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 331e41f4b71Sopenharmony_ci listener.onDataDelete(index); 332e41f4b71Sopenharmony_ci }) 333e41f4b71Sopenharmony_ci } 334e41f4b71Sopenharmony_ci 335e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 336e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 337e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 338e41f4b71Sopenharmony_ci }) 339e41f4b71Sopenharmony_ci } 340e41f4b71Sopenharmony_ci} 341e41f4b71Sopenharmony_ci 342e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 343e41f4b71Sopenharmony_ci private dataArray: string[] = []; 344e41f4b71Sopenharmony_ci 345e41f4b71Sopenharmony_ci public totalCount(): number { 346e41f4b71Sopenharmony_ci return this.dataArray.length; 347e41f4b71Sopenharmony_ci } 348e41f4b71Sopenharmony_ci 349e41f4b71Sopenharmony_ci public getData(index: number): string { 350e41f4b71Sopenharmony_ci return this.dataArray[index]; 351e41f4b71Sopenharmony_ci } 352e41f4b71Sopenharmony_ci 353e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 354e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 355e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 356e41f4b71Sopenharmony_ci } 357e41f4b71Sopenharmony_ci 358e41f4b71Sopenharmony_ci public pushData(data: string): void { 359e41f4b71Sopenharmony_ci this.dataArray.push(data); 360e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 361e41f4b71Sopenharmony_ci } 362e41f4b71Sopenharmony_ci} 363e41f4b71Sopenharmony_ci 364e41f4b71Sopenharmony_ci@Entry 365e41f4b71Sopenharmony_ci@Component 366e41f4b71Sopenharmony_cistruct MyComponent { 367e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 368e41f4b71Sopenharmony_ci 369e41f4b71Sopenharmony_ci aboutToAppear() { 370e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 371e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 372e41f4b71Sopenharmony_ci } 373e41f4b71Sopenharmony_ci } 374e41f4b71Sopenharmony_ci 375e41f4b71Sopenharmony_ci build() { 376e41f4b71Sopenharmony_ci List({ space: 3 }) { 377e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 378e41f4b71Sopenharmony_ci ListItem() { 379e41f4b71Sopenharmony_ci Row() { 380e41f4b71Sopenharmony_ci Text(item).fontSize(50) 381e41f4b71Sopenharmony_ci .onAppear(() => { 382e41f4b71Sopenharmony_ci console.info("appear:" + item) 383e41f4b71Sopenharmony_ci }) 384e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 385e41f4b71Sopenharmony_ci } 386e41f4b71Sopenharmony_ci .onClick(() => { 387e41f4b71Sopenharmony_ci // Click to add a child component. 388e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${this.data.totalCount()}`); 389e41f4b71Sopenharmony_ci }) 390e41f4b71Sopenharmony_ci }, (item: string) => item) 391e41f4b71Sopenharmony_ci }.cachedCount(5) 392e41f4b71Sopenharmony_ci } 393e41f4b71Sopenharmony_ci} 394e41f4b71Sopenharmony_ci``` 395e41f4b71Sopenharmony_ci 396e41f4b71Sopenharmony_ciWhen the child component of **LazyForEach** is clicked, the **pushData** method of the data source is called first. This method adds data to the end of the data source and then calls the **notifyDataAdd** method. In the **notifyDataAdd** method, the **listener.onDataAdd** method is called to notify **LazyForEach** that data is added, and LazyForEach creates a child component at the position indicated by the specified index. 397e41f4b71Sopenharmony_ci 398e41f4b71Sopenharmony_ciThe figure below shows the effect. 399e41f4b71Sopenharmony_ci 400e41f4b71Sopenharmony_ci**Figure 3** Adding data to LazyForEach 401e41f4b71Sopenharmony_ci 402e41f4b71Sopenharmony_ci 403e41f4b71Sopenharmony_ci- ### Deleting Data 404e41f4b71Sopenharmony_ci 405e41f4b71Sopenharmony_ci```ts 406e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 407e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 408e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 409e41f4b71Sopenharmony_ci 410e41f4b71Sopenharmony_ci public totalCount(): number { 411e41f4b71Sopenharmony_ci return 0; 412e41f4b71Sopenharmony_ci } 413e41f4b71Sopenharmony_ci 414e41f4b71Sopenharmony_ci public getData(index: number): string { 415e41f4b71Sopenharmony_ci return this.originDataArray[index]; 416e41f4b71Sopenharmony_ci } 417e41f4b71Sopenharmony_ci 418e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 419e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 420e41f4b71Sopenharmony_ci console.info('add listener'); 421e41f4b71Sopenharmony_ci this.listeners.push(listener); 422e41f4b71Sopenharmony_ci } 423e41f4b71Sopenharmony_ci } 424e41f4b71Sopenharmony_ci 425e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 426e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 427e41f4b71Sopenharmony_ci if (pos >= 0) { 428e41f4b71Sopenharmony_ci console.info('remove listener'); 429e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 430e41f4b71Sopenharmony_ci } 431e41f4b71Sopenharmony_ci } 432e41f4b71Sopenharmony_ci 433e41f4b71Sopenharmony_ci notifyDataReload(): void { 434e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 435e41f4b71Sopenharmony_ci listener.onDataReloaded(); 436e41f4b71Sopenharmony_ci }) 437e41f4b71Sopenharmony_ci } 438e41f4b71Sopenharmony_ci 439e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 440e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 441e41f4b71Sopenharmony_ci listener.onDataAdd(index); 442e41f4b71Sopenharmony_ci }) 443e41f4b71Sopenharmony_ci } 444e41f4b71Sopenharmony_ci 445e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 446e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 447e41f4b71Sopenharmony_ci listener.onDataChange(index); 448e41f4b71Sopenharmony_ci }) 449e41f4b71Sopenharmony_ci } 450e41f4b71Sopenharmony_ci 451e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 452e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 453e41f4b71Sopenharmony_ci listener.onDataDelete(index); 454e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]); 455e41f4b71Sopenharmony_ci }) 456e41f4b71Sopenharmony_ci } 457e41f4b71Sopenharmony_ci 458e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 459e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 460e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 461e41f4b71Sopenharmony_ci }) 462e41f4b71Sopenharmony_ci } 463e41f4b71Sopenharmony_ci} 464e41f4b71Sopenharmony_ci 465e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 466e41f4b71Sopenharmony_ci dataArray: string[] = []; 467e41f4b71Sopenharmony_ci 468e41f4b71Sopenharmony_ci public totalCount(): number { 469e41f4b71Sopenharmony_ci return this.dataArray.length; 470e41f4b71Sopenharmony_ci } 471e41f4b71Sopenharmony_ci 472e41f4b71Sopenharmony_ci public getData(index: number): string { 473e41f4b71Sopenharmony_ci return this.dataArray[index]; 474e41f4b71Sopenharmony_ci } 475e41f4b71Sopenharmony_ci 476e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 477e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 478e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 479e41f4b71Sopenharmony_ci } 480e41f4b71Sopenharmony_ci 481e41f4b71Sopenharmony_ci public pushData(data: string): void { 482e41f4b71Sopenharmony_ci this.dataArray.push(data); 483e41f4b71Sopenharmony_ci } 484e41f4b71Sopenharmony_ci 485e41f4b71Sopenharmony_ci public deleteData(index: number): void { 486e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 487e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 488e41f4b71Sopenharmony_ci } 489e41f4b71Sopenharmony_ci} 490e41f4b71Sopenharmony_ci 491e41f4b71Sopenharmony_ci@Entry 492e41f4b71Sopenharmony_ci@Component 493e41f4b71Sopenharmony_cistruct MyComponent { 494e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 495e41f4b71Sopenharmony_ci 496e41f4b71Sopenharmony_ci aboutToAppear() { 497e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 498e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 499e41f4b71Sopenharmony_ci } 500e41f4b71Sopenharmony_ci } 501e41f4b71Sopenharmony_ci 502e41f4b71Sopenharmony_ci build() { 503e41f4b71Sopenharmony_ci List({ space: 3 }) { 504e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 505e41f4b71Sopenharmony_ci ListItem() { 506e41f4b71Sopenharmony_ci Row() { 507e41f4b71Sopenharmony_ci Text(item).fontSize(50) 508e41f4b71Sopenharmony_ci .onAppear(() => { 509e41f4b71Sopenharmony_ci console.info("appear:" + item) 510e41f4b71Sopenharmony_ci }) 511e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 512e41f4b71Sopenharmony_ci } 513e41f4b71Sopenharmony_ci .onClick(() => { 514e41f4b71Sopenharmony_ci // Click to delete a child component. 515e41f4b71Sopenharmony_ci this.data.deleteData(this.data.dataArray.indexOf(item)); 516e41f4b71Sopenharmony_ci }) 517e41f4b71Sopenharmony_ci }, (item: string) => item) 518e41f4b71Sopenharmony_ci }.cachedCount(5) 519e41f4b71Sopenharmony_ci } 520e41f4b71Sopenharmony_ci} 521e41f4b71Sopenharmony_ci``` 522e41f4b71Sopenharmony_ci 523e41f4b71Sopenharmony_ciWhen the child component of **LazyForEach** is clicked, the **deleteData** method of the data source is called first. This method deletes data that matches the specified index from the data source and then calls the **notifyDataDelete** method. In the **notifyDataDelete** method, the **listener.onDataDelete** method is called to notify **LazyForEach** that data is deleted, and **LazyForEach** deletes the child component at the position indicated by the specified index. 524e41f4b71Sopenharmony_ci 525e41f4b71Sopenharmony_ciThe figure below shows the effect. 526e41f4b71Sopenharmony_ci 527e41f4b71Sopenharmony_ci**Figure 4** Deleting data from LazyForEach 528e41f4b71Sopenharmony_ci 529e41f4b71Sopenharmony_ci 530e41f4b71Sopenharmony_ci- ### Swapping Data 531e41f4b71Sopenharmony_ci 532e41f4b71Sopenharmony_ci```ts 533e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 534e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 535e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 536e41f4b71Sopenharmony_ci 537e41f4b71Sopenharmony_ci public totalCount(): number { 538e41f4b71Sopenharmony_ci return 0; 539e41f4b71Sopenharmony_ci } 540e41f4b71Sopenharmony_ci 541e41f4b71Sopenharmony_ci public getData(index: number): string { 542e41f4b71Sopenharmony_ci return this.originDataArray[index]; 543e41f4b71Sopenharmony_ci } 544e41f4b71Sopenharmony_ci 545e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 546e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 547e41f4b71Sopenharmony_ci console.info('add listener'); 548e41f4b71Sopenharmony_ci this.listeners.push(listener); 549e41f4b71Sopenharmony_ci } 550e41f4b71Sopenharmony_ci } 551e41f4b71Sopenharmony_ci 552e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 553e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 554e41f4b71Sopenharmony_ci if (pos >= 0) { 555e41f4b71Sopenharmony_ci console.info('remove listener'); 556e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 557e41f4b71Sopenharmony_ci } 558e41f4b71Sopenharmony_ci } 559e41f4b71Sopenharmony_ci 560e41f4b71Sopenharmony_ci notifyDataReload(): void { 561e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 562e41f4b71Sopenharmony_ci listener.onDataReloaded(); 563e41f4b71Sopenharmony_ci }) 564e41f4b71Sopenharmony_ci } 565e41f4b71Sopenharmony_ci 566e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 567e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 568e41f4b71Sopenharmony_ci listener.onDataAdd(index); 569e41f4b71Sopenharmony_ci }) 570e41f4b71Sopenharmony_ci } 571e41f4b71Sopenharmony_ci 572e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 573e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 574e41f4b71Sopenharmony_ci listener.onDataChange(index); 575e41f4b71Sopenharmony_ci }) 576e41f4b71Sopenharmony_ci } 577e41f4b71Sopenharmony_ci 578e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 579e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 580e41f4b71Sopenharmony_ci listener.onDataDelete(index); 581e41f4b71Sopenharmony_ci }) 582e41f4b71Sopenharmony_ci } 583e41f4b71Sopenharmony_ci 584e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 585e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 586e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 587e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange () 588e41f4b71Sopenharmony_ci // [{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]); 589e41f4b71Sopenharmony_ci }) 590e41f4b71Sopenharmony_ci } 591e41f4b71Sopenharmony_ci} 592e41f4b71Sopenharmony_ci 593e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 594e41f4b71Sopenharmony_ci dataArray: string[] = []; 595e41f4b71Sopenharmony_ci 596e41f4b71Sopenharmony_ci public totalCount(): number { 597e41f4b71Sopenharmony_ci return this.dataArray.length; 598e41f4b71Sopenharmony_ci } 599e41f4b71Sopenharmony_ci 600e41f4b71Sopenharmony_ci public getData(index: number): string { 601e41f4b71Sopenharmony_ci return this.dataArray[index]; 602e41f4b71Sopenharmony_ci } 603e41f4b71Sopenharmony_ci 604e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 605e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 606e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 607e41f4b71Sopenharmony_ci } 608e41f4b71Sopenharmony_ci 609e41f4b71Sopenharmony_ci public pushData(data: string): void { 610e41f4b71Sopenharmony_ci this.dataArray.push(data); 611e41f4b71Sopenharmony_ci } 612e41f4b71Sopenharmony_ci 613e41f4b71Sopenharmony_ci public deleteData(index: number): void { 614e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 615e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 616e41f4b71Sopenharmony_ci } 617e41f4b71Sopenharmony_ci 618e41f4b71Sopenharmony_ci public moveData(from: number, to: number): void { 619e41f4b71Sopenharmony_ci let temp: string = this.dataArray[from]; 620e41f4b71Sopenharmony_ci this.dataArray[from] = this.dataArray[to]; 621e41f4b71Sopenharmony_ci this.dataArray[to] = temp; 622e41f4b71Sopenharmony_ci this.notifyDataMove(from, to); 623e41f4b71Sopenharmony_ci } 624e41f4b71Sopenharmony_ci} 625e41f4b71Sopenharmony_ci 626e41f4b71Sopenharmony_ci@Entry 627e41f4b71Sopenharmony_ci@Component 628e41f4b71Sopenharmony_cistruct MyComponent { 629e41f4b71Sopenharmony_ci private moved: number[] = []; 630e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 631e41f4b71Sopenharmony_ci 632e41f4b71Sopenharmony_ci aboutToAppear() { 633e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 634e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 635e41f4b71Sopenharmony_ci } 636e41f4b71Sopenharmony_ci } 637e41f4b71Sopenharmony_ci 638e41f4b71Sopenharmony_ci build() { 639e41f4b71Sopenharmony_ci List({ space: 3 }) { 640e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 641e41f4b71Sopenharmony_ci ListItem() { 642e41f4b71Sopenharmony_ci Row() { 643e41f4b71Sopenharmony_ci Text(item).fontSize(50) 644e41f4b71Sopenharmony_ci .onAppear(() => { 645e41f4b71Sopenharmony_ci console.info("appear:" + item) 646e41f4b71Sopenharmony_ci }) 647e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 648e41f4b71Sopenharmony_ci } 649e41f4b71Sopenharmony_ci .onClick(() => { 650e41f4b71Sopenharmony_ci this.moved.push(this.data.dataArray.indexOf(item)); 651e41f4b71Sopenharmony_ci if (this.moved.length === 2) { 652e41f4b71Sopenharmony_ci // Click to exchange child components. 653e41f4b71Sopenharmony_ci this.data.moveData(this.moved[0], this.moved[1]); 654e41f4b71Sopenharmony_ci this.moved = []; 655e41f4b71Sopenharmony_ci } 656e41f4b71Sopenharmony_ci }) 657e41f4b71Sopenharmony_ci }, (item: string) => item) 658e41f4b71Sopenharmony_ci }.cachedCount(5) 659e41f4b71Sopenharmony_ci } 660e41f4b71Sopenharmony_ci} 661e41f4b71Sopenharmony_ci``` 662e41f4b71Sopenharmony_ci 663e41f4b71Sopenharmony_ciWhen a child component of **LazyForEach** is clicked, the index of the data to be moved is stored in the **moved** member variable. When another child component of **LazyForEach** is clicked, the first child component clicked is moved here. The **moveData** method of the data source is called to move the data from the original location to the expected location, after which the **notifyDataMove** method is called. In the **notifyDataMove** method, the **listener.onDataMove** method is called to notify **LazyForEach** that data needs to be moved.** LazyForEach** then swaps data between the **from** and **to** positions. 664e41f4b71Sopenharmony_ci 665e41f4b71Sopenharmony_ciThe figure below shows the effect. 666e41f4b71Sopenharmony_ci 667e41f4b71Sopenharmony_ci**Figure 5** Swapping data in LazyForEach 668e41f4b71Sopenharmony_ci 669e41f4b71Sopenharmony_ci 670e41f4b71Sopenharmony_ci- ### Changing a Data Item 671e41f4b71Sopenharmony_ci 672e41f4b71Sopenharmony_ci```ts 673e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 674e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 675e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 676e41f4b71Sopenharmony_ci 677e41f4b71Sopenharmony_ci public totalCount(): number { 678e41f4b71Sopenharmony_ci return 0; 679e41f4b71Sopenharmony_ci } 680e41f4b71Sopenharmony_ci 681e41f4b71Sopenharmony_ci public getData(index: number): string { 682e41f4b71Sopenharmony_ci return this.originDataArray[index]; 683e41f4b71Sopenharmony_ci } 684e41f4b71Sopenharmony_ci 685e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 686e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 687e41f4b71Sopenharmony_ci console.info('add listener'); 688e41f4b71Sopenharmony_ci this.listeners.push(listener); 689e41f4b71Sopenharmony_ci } 690e41f4b71Sopenharmony_ci } 691e41f4b71Sopenharmony_ci 692e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 693e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 694e41f4b71Sopenharmony_ci if (pos >= 0) { 695e41f4b71Sopenharmony_ci console.info('remove listener'); 696e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 697e41f4b71Sopenharmony_ci } 698e41f4b71Sopenharmony_ci } 699e41f4b71Sopenharmony_ci 700e41f4b71Sopenharmony_ci notifyDataReload(): void { 701e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 702e41f4b71Sopenharmony_ci listener.onDataReloaded(); 703e41f4b71Sopenharmony_ci }) 704e41f4b71Sopenharmony_ci } 705e41f4b71Sopenharmony_ci 706e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 707e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 708e41f4b71Sopenharmony_ci listener.onDataAdd(index); 709e41f4b71Sopenharmony_ci }) 710e41f4b71Sopenharmony_ci } 711e41f4b71Sopenharmony_ci 712e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 713e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 714e41f4b71Sopenharmony_ci listener.onDataChange(index); 715e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]); 716e41f4b71Sopenharmony_ci }) 717e41f4b71Sopenharmony_ci } 718e41f4b71Sopenharmony_ci 719e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 720e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 721e41f4b71Sopenharmony_ci listener.onDataDelete(index); 722e41f4b71Sopenharmony_ci }) 723e41f4b71Sopenharmony_ci } 724e41f4b71Sopenharmony_ci 725e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 726e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 727e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 728e41f4b71Sopenharmony_ci }) 729e41f4b71Sopenharmony_ci } 730e41f4b71Sopenharmony_ci} 731e41f4b71Sopenharmony_ci 732e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 733e41f4b71Sopenharmony_ci private dataArray: string[] = []; 734e41f4b71Sopenharmony_ci 735e41f4b71Sopenharmony_ci public totalCount(): number { 736e41f4b71Sopenharmony_ci return this.dataArray.length; 737e41f4b71Sopenharmony_ci } 738e41f4b71Sopenharmony_ci 739e41f4b71Sopenharmony_ci public getData(index: number): string { 740e41f4b71Sopenharmony_ci return this.dataArray[index]; 741e41f4b71Sopenharmony_ci } 742e41f4b71Sopenharmony_ci 743e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 744e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 745e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 746e41f4b71Sopenharmony_ci } 747e41f4b71Sopenharmony_ci 748e41f4b71Sopenharmony_ci public pushData(data: string): void { 749e41f4b71Sopenharmony_ci this.dataArray.push(data); 750e41f4b71Sopenharmony_ci } 751e41f4b71Sopenharmony_ci 752e41f4b71Sopenharmony_ci public deleteData(index: number): void { 753e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 754e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 755e41f4b71Sopenharmony_ci } 756e41f4b71Sopenharmony_ci 757e41f4b71Sopenharmony_ci public changeData(index: number, data: string): void { 758e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1, data); 759e41f4b71Sopenharmony_ci this.notifyDataChange(index); 760e41f4b71Sopenharmony_ci } 761e41f4b71Sopenharmony_ci} 762e41f4b71Sopenharmony_ci 763e41f4b71Sopenharmony_ci@Entry 764e41f4b71Sopenharmony_ci@Component 765e41f4b71Sopenharmony_cistruct MyComponent { 766e41f4b71Sopenharmony_ci private moved: number[] = []; 767e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 768e41f4b71Sopenharmony_ci 769e41f4b71Sopenharmony_ci aboutToAppear() { 770e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 771e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 772e41f4b71Sopenharmony_ci } 773e41f4b71Sopenharmony_ci } 774e41f4b71Sopenharmony_ci 775e41f4b71Sopenharmony_ci 776e41f4b71Sopenharmony_ci build() { 777e41f4b71Sopenharmony_ci List({ space: 3 }) { 778e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 779e41f4b71Sopenharmony_ci ListItem() { 780e41f4b71Sopenharmony_ci Row() { 781e41f4b71Sopenharmony_ci Text(item).fontSize(50) 782e41f4b71Sopenharmony_ci .onAppear(() => { 783e41f4b71Sopenharmony_ci console.info("appear:" + item) 784e41f4b71Sopenharmony_ci }) 785e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 786e41f4b71Sopenharmony_ci } 787e41f4b71Sopenharmony_ci .onClick(() => { 788e41f4b71Sopenharmony_ci this.data.changeData(index, item + '00'); 789e41f4b71Sopenharmony_ci }) 790e41f4b71Sopenharmony_ci }, (item: string) => item) 791e41f4b71Sopenharmony_ci }.cachedCount(5) 792e41f4b71Sopenharmony_ci } 793e41f4b71Sopenharmony_ci} 794e41f4b71Sopenharmony_ci``` 795e41f4b71Sopenharmony_ci 796e41f4b71Sopenharmony_ciWhen the child component of **LazyForEach** is clicked, the data is changed first, and then the **changeData** method of the data source is called. In this method, the **notifyDataChange** method is called. In the **notifyDataChange** method, the **listener.onDataChange** method is called to notify **LazyForEach** of data changes. **LazyForEach** then rebuilds the child component that matches the specified index. 797e41f4b71Sopenharmony_ci 798e41f4b71Sopenharmony_ciThe figure below shows the effect. 799e41f4b71Sopenharmony_ci 800e41f4b71Sopenharmony_ci**Figure 6** Changing a data item in LazyForEach 801e41f4b71Sopenharmony_ci 802e41f4b71Sopenharmony_ci 803e41f4b71Sopenharmony_ci- ### Changing Multiple Data Items 804e41f4b71Sopenharmony_ci 805e41f4b71Sopenharmony_ci```ts 806e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 807e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 808e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 809e41f4b71Sopenharmony_ci 810e41f4b71Sopenharmony_ci public totalCount(): number { 811e41f4b71Sopenharmony_ci return 0; 812e41f4b71Sopenharmony_ci } 813e41f4b71Sopenharmony_ci 814e41f4b71Sopenharmony_ci public getData(index: number): string { 815e41f4b71Sopenharmony_ci return this.originDataArray[index]; 816e41f4b71Sopenharmony_ci } 817e41f4b71Sopenharmony_ci 818e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 819e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 820e41f4b71Sopenharmony_ci console.info('add listener'); 821e41f4b71Sopenharmony_ci this.listeners.push(listener); 822e41f4b71Sopenharmony_ci } 823e41f4b71Sopenharmony_ci } 824e41f4b71Sopenharmony_ci 825e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 826e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 827e41f4b71Sopenharmony_ci if (pos >= 0) { 828e41f4b71Sopenharmony_ci console.info('remove listener'); 829e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 830e41f4b71Sopenharmony_ci } 831e41f4b71Sopenharmony_ci } 832e41f4b71Sopenharmony_ci 833e41f4b71Sopenharmony_ci notifyDataReload(): void { 834e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 835e41f4b71Sopenharmony_ci listener.onDataReloaded(); 836e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.RELOAD}]); 837e41f4b71Sopenharmony_ci }) 838e41f4b71Sopenharmony_ci } 839e41f4b71Sopenharmony_ci 840e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 841e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 842e41f4b71Sopenharmony_ci listener.onDataAdd(index); 843e41f4b71Sopenharmony_ci }) 844e41f4b71Sopenharmony_ci } 845e41f4b71Sopenharmony_ci 846e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 847e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 848e41f4b71Sopenharmony_ci listener.onDataChange(index); 849e41f4b71Sopenharmony_ci }) 850e41f4b71Sopenharmony_ci } 851e41f4b71Sopenharmony_ci 852e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 853e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 854e41f4b71Sopenharmony_ci listener.onDataDelete(index); 855e41f4b71Sopenharmony_ci }) 856e41f4b71Sopenharmony_ci } 857e41f4b71Sopenharmony_ci 858e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 859e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 860e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 861e41f4b71Sopenharmony_ci }) 862e41f4b71Sopenharmony_ci } 863e41f4b71Sopenharmony_ci} 864e41f4b71Sopenharmony_ci 865e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 866e41f4b71Sopenharmony_ci private dataArray: string[] = []; 867e41f4b71Sopenharmony_ci 868e41f4b71Sopenharmony_ci public totalCount(): number { 869e41f4b71Sopenharmony_ci return this.dataArray.length; 870e41f4b71Sopenharmony_ci } 871e41f4b71Sopenharmony_ci 872e41f4b71Sopenharmony_ci public getData(index: number): string { 873e41f4b71Sopenharmony_ci return this.dataArray[index]; 874e41f4b71Sopenharmony_ci } 875e41f4b71Sopenharmony_ci 876e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 877e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 878e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 879e41f4b71Sopenharmony_ci } 880e41f4b71Sopenharmony_ci 881e41f4b71Sopenharmony_ci public pushData(data: string): void { 882e41f4b71Sopenharmony_ci this.dataArray.push(data); 883e41f4b71Sopenharmony_ci } 884e41f4b71Sopenharmony_ci 885e41f4b71Sopenharmony_ci public deleteData(index: number): void { 886e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 887e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 888e41f4b71Sopenharmony_ci } 889e41f4b71Sopenharmony_ci 890e41f4b71Sopenharmony_ci public changeData(index: number): void { 891e41f4b71Sopenharmony_ci this.notifyDataChange(index); 892e41f4b71Sopenharmony_ci } 893e41f4b71Sopenharmony_ci 894e41f4b71Sopenharmony_ci public reloadData(): void { 895e41f4b71Sopenharmony_ci this.notifyDataReload(); 896e41f4b71Sopenharmony_ci } 897e41f4b71Sopenharmony_ci 898e41f4b71Sopenharmony_ci public modifyAllData(): void { 899e41f4b71Sopenharmony_ci this.dataArray = this.dataArray.map((item: string) => { 900e41f4b71Sopenharmony_ci return item + '0'; 901e41f4b71Sopenharmony_ci }) 902e41f4b71Sopenharmony_ci } 903e41f4b71Sopenharmony_ci} 904e41f4b71Sopenharmony_ci 905e41f4b71Sopenharmony_ci@Entry 906e41f4b71Sopenharmony_ci@Component 907e41f4b71Sopenharmony_cistruct MyComponent { 908e41f4b71Sopenharmony_ci private moved: number[] = []; 909e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 910e41f4b71Sopenharmony_ci 911e41f4b71Sopenharmony_ci aboutToAppear() { 912e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 913e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 914e41f4b71Sopenharmony_ci } 915e41f4b71Sopenharmony_ci } 916e41f4b71Sopenharmony_ci 917e41f4b71Sopenharmony_ci build() { 918e41f4b71Sopenharmony_ci List({ space: 3 }) { 919e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 920e41f4b71Sopenharmony_ci ListItem() { 921e41f4b71Sopenharmony_ci Row() { 922e41f4b71Sopenharmony_ci Text(item).fontSize(50) 923e41f4b71Sopenharmony_ci .onAppear(() => { 924e41f4b71Sopenharmony_ci console.info("appear:" + item) 925e41f4b71Sopenharmony_ci }) 926e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 927e41f4b71Sopenharmony_ci } 928e41f4b71Sopenharmony_ci .onClick(() => { 929e41f4b71Sopenharmony_ci this.data.modifyAllData(); 930e41f4b71Sopenharmony_ci this.data.reloadData(); 931e41f4b71Sopenharmony_ci }) 932e41f4b71Sopenharmony_ci }, (item: string) => item) 933e41f4b71Sopenharmony_ci }.cachedCount(5) 934e41f4b71Sopenharmony_ci } 935e41f4b71Sopenharmony_ci} 936e41f4b71Sopenharmony_ci``` 937e41f4b71Sopenharmony_ci 938e41f4b71Sopenharmony_ciWhen a child component of **LazyForEach** is clicked, the **modifyAllData** method of the data source is called to change all data items, and then the **reloadData** method of the data source is called. In this method, the **notifyDataReload** method is called. In the **notifyDataReload** method, the **listener.onDataReloaded** method is called to notify **LazyForEach** that all subnodes need to be rebuilt. **LazyForEach** compares the keys of all original data items with those of all new data items on a one-by-one basis. If the keys are the same, the cache is used. If the keys are different, the child component is rebuilt. 939e41f4b71Sopenharmony_ci 940e41f4b71Sopenharmony_ciThe figure below shows the effect. 941e41f4b71Sopenharmony_ci 942e41f4b71Sopenharmony_ci**Figure 7** Changing multiple data items in LazyForEach 943e41f4b71Sopenharmony_ci 944e41f4b71Sopenharmony_ci 945e41f4b71Sopenharmony_ci- ### Precisely Changing Data in Batches 946e41f4b71Sopenharmony_ci 947e41f4b71Sopenharmony_ci```ts 948e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 949e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 950e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 951e41f4b71Sopenharmony_ci 952e41f4b71Sopenharmony_ci public totalCount(): number { 953e41f4b71Sopenharmony_ci return 0; 954e41f4b71Sopenharmony_ci } 955e41f4b71Sopenharmony_ci 956e41f4b71Sopenharmony_ci public getData(index: number): string { 957e41f4b71Sopenharmony_ci return this.originDataArray[index]; 958e41f4b71Sopenharmony_ci } 959e41f4b71Sopenharmony_ci 960e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 961e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 962e41f4b71Sopenharmony_ci console.info('add listener'); 963e41f4b71Sopenharmony_ci this.listeners.push(listener); 964e41f4b71Sopenharmony_ci } 965e41f4b71Sopenharmony_ci } 966e41f4b71Sopenharmony_ci 967e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 968e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 969e41f4b71Sopenharmony_ci if (pos >= 0) { 970e41f4b71Sopenharmony_ci console.info('remove listener'); 971e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 972e41f4b71Sopenharmony_ci } 973e41f4b71Sopenharmony_ci } 974e41f4b71Sopenharmony_ci 975e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]): void { 976e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 977e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 978e41f4b71Sopenharmony_ci }) 979e41f4b71Sopenharmony_ci } 980e41f4b71Sopenharmony_ci} 981e41f4b71Sopenharmony_ci 982e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 983e41f4b71Sopenharmony_ci private dataArray: string[] = []; 984e41f4b71Sopenharmony_ci 985e41f4b71Sopenharmony_ci public totalCount(): number { 986e41f4b71Sopenharmony_ci return this.dataArray.length; 987e41f4b71Sopenharmony_ci } 988e41f4b71Sopenharmony_ci 989e41f4b71Sopenharmony_ci public getData(index: number): string { 990e41f4b71Sopenharmony_ci return this.dataArray[index]; 991e41f4b71Sopenharmony_ci } 992e41f4b71Sopenharmony_ci 993e41f4b71Sopenharmony_ci public operateData(): void { 994e41f4b71Sopenharmony_ci console.info(JSON.stringify(this.dataArray)); 995e41f4b71Sopenharmony_ci this.dataArray.splice(4, 0, this.dataArray[1]); 996e41f4b71Sopenharmony_ci this.dataArray.splice(1, 1); 997e41f4b71Sopenharmony_ci let temp = this.dataArray[4]; 998e41f4b71Sopenharmony_ci this.dataArray[4] = this.dataArray[6]; 999e41f4b71Sopenharmony_ci this.dataArray[6] = temp 1000e41f4b71Sopenharmony_ci this.dataArray.splice(8, 0, 'Hello 1', 'Hello 2'); 1001e41f4b71Sopenharmony_ci this.dataArray.splice(12, 2); 1002e41f4b71Sopenharmony_ci console.info(JSON.stringify(this.dataArray)); 1003e41f4b71Sopenharmony_ci this.notifyDatasetChange([ 1004e41f4b71Sopenharmony_ci { type: DataOperationType.MOVE, index: { from: 1, to: 3 } }, 1005e41f4b71Sopenharmony_ci { type: DataOperationType.EXCHANGE, index: { start: 4, end: 6 } }, 1006e41f4b71Sopenharmony_ci { type: DataOperationType.ADD, index: 8, count: 2 }, 1007e41f4b71Sopenharmony_ci { type: DataOperationType.DELETE, index: 10, count: 2 }]); 1008e41f4b71Sopenharmony_ci } 1009e41f4b71Sopenharmony_ci 1010e41f4b71Sopenharmony_ci public init(): void { 1011e41f4b71Sopenharmony_ci this.dataArray.splice(0, 0, 'Hello a', 'Hello b', 'Hello c', 'Hello d', 'Hello e', 'Hello f', 'Hello g', 'Hello h', 1012e41f4b71Sopenharmony_ci 'Hello i', 'Hello j', 'Hello k', 'Hello l', 'Hello m', 'Hello n', 'Hello o', 'Hello p', 'Hello q', 'Hello r'); 1013e41f4b71Sopenharmony_ci } 1014e41f4b71Sopenharmony_ci} 1015e41f4b71Sopenharmony_ci 1016e41f4b71Sopenharmony_ci@Entry 1017e41f4b71Sopenharmony_ci@Component 1018e41f4b71Sopenharmony_cistruct MyComponent { 1019e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1020e41f4b71Sopenharmony_ci 1021e41f4b71Sopenharmony_ci aboutToAppear() { 1022e41f4b71Sopenharmony_ci this.data.init() 1023e41f4b71Sopenharmony_ci } 1024e41f4b71Sopenharmony_ci 1025e41f4b71Sopenharmony_ci build() { 1026e41f4b71Sopenharmony_ci Column() { 1027e41f4b71Sopenharmony_ci Text('Move the second item to where the fourth item is located, exchange the fifth and seventh data items, add "Hello 1" "Hello 2" to the ninth item, and delete two items starting from the eleventh item') 1028e41f4b71Sopenharmony_ci .fontSize(10) 1029e41f4b71Sopenharmony_ci .backgroundColor(Color.Blue) 1030e41f4b71Sopenharmony_ci .fontColor(Color.White) 1031e41f4b71Sopenharmony_ci .borderRadius(50) 1032e41f4b71Sopenharmony_ci .padding(5) 1033e41f4b71Sopenharmony_ci .onClick(() => { 1034e41f4b71Sopenharmony_ci this.data.operateData(); 1035e41f4b71Sopenharmony_ci }) 1036e41f4b71Sopenharmony_ci List({ space: 3 }) { 1037e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1038e41f4b71Sopenharmony_ci ListItem() { 1039e41f4b71Sopenharmony_ci Row() { 1040e41f4b71Sopenharmony_ci Text(item).fontSize(35) 1041e41f4b71Sopenharmony_ci .onAppear(() => { 1042e41f4b71Sopenharmony_ci console.info("appear:" + item) 1043e41f4b71Sopenharmony_ci }) 1044e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1045e41f4b71Sopenharmony_ci } 1046e41f4b71Sopenharmony_ci 1047e41f4b71Sopenharmony_ci }, (item: string) => item + new Date().getTime()) 1048e41f4b71Sopenharmony_ci }.cachedCount(5) 1049e41f4b71Sopenharmony_ci } 1050e41f4b71Sopenharmony_ci } 1051e41f4b71Sopenharmony_ci} 1052e41f4b71Sopenharmony_ci``` 1053e41f4b71Sopenharmony_ci 1054e41f4b71Sopenharmony_ciThe **onDatasetChange** API notifies **LazyForEach** of the operations to be performed at once. In the preceding example, **LazyForEach** adds, deletes, moves, and exchanges data at the same time. 1055e41f4b71Sopenharmony_ci 1056e41f4b71Sopenharmony_ci**Figure 8** Changing multiple data items in LazyForEach 1057e41f4b71Sopenharmony_ci 1058e41f4b71Sopenharmony_ci 1059e41f4b71Sopenharmony_ci 1060e41f4b71Sopenharmony_ciIn the second example, values are directly changed in the array without using **splice()**. Result of **operations** is directly obtained by comparing the original array with the new array. 1061e41f4b71Sopenharmony_ci```ts 1062e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1063e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1064e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1065e41f4b71Sopenharmony_ci 1066e41f4b71Sopenharmony_ci public totalCount(): number { 1067e41f4b71Sopenharmony_ci return 0; 1068e41f4b71Sopenharmony_ci } 1069e41f4b71Sopenharmony_ci 1070e41f4b71Sopenharmony_ci public getData(index: number): string { 1071e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1072e41f4b71Sopenharmony_ci } 1073e41f4b71Sopenharmony_ci 1074e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1075e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1076e41f4b71Sopenharmony_ci console.info('add listener'); 1077e41f4b71Sopenharmony_ci this.listeners.push(listener); 1078e41f4b71Sopenharmony_ci } 1079e41f4b71Sopenharmony_ci } 1080e41f4b71Sopenharmony_ci 1081e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1082e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1083e41f4b71Sopenharmony_ci if (pos >= 0) { 1084e41f4b71Sopenharmony_ci console.info('remove listener'); 1085e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1086e41f4b71Sopenharmony_ci } 1087e41f4b71Sopenharmony_ci } 1088e41f4b71Sopenharmony_ci 1089e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]): void { 1090e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1091e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 1092e41f4b71Sopenharmony_ci }) 1093e41f4b71Sopenharmony_ci } 1094e41f4b71Sopenharmony_ci} 1095e41f4b71Sopenharmony_ci 1096e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1097e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1098e41f4b71Sopenharmony_ci 1099e41f4b71Sopenharmony_ci public totalCount(): number { 1100e41f4b71Sopenharmony_ci return this.dataArray.length; 1101e41f4b71Sopenharmony_ci } 1102e41f4b71Sopenharmony_ci 1103e41f4b71Sopenharmony_ci public getData(index: number): string { 1104e41f4b71Sopenharmony_ci return this.dataArray[index]; 1105e41f4b71Sopenharmony_ci } 1106e41f4b71Sopenharmony_ci 1107e41f4b71Sopenharmony_ci public operateData(): void { 1108e41f4b71Sopenharmony_ci this.dataArray = 1109e41f4b71Sopenharmony_ci ['Hello x', 'Hello 1', 'Hello 2', 'Hello b', 'Hello c', 'Hello e', 'Hello d', 'Hello f', 'Hello g', 'Hello h'] 1110e41f4b71Sopenharmony_ci this.notifyDatasetChange([ 1111e41f4b71Sopenharmony_ci { type: DataOperationType.CHANGE, index: 0 }, 1112e41f4b71Sopenharmony_ci { type: DataOperationType.ADD, index: 1, count: 2 }, 1113e41f4b71Sopenharmony_ci { type: DataOperationType.EXCHANGE, index: { start: 3, end: 4 } }, 1114e41f4b71Sopenharmony_ci ]); 1115e41f4b71Sopenharmony_ci } 1116e41f4b71Sopenharmony_ci 1117e41f4b71Sopenharmony_ci public init(): void { 1118e41f4b71Sopenharmony_ci this.dataArray = ['Hello a', 'Hello b', 'Hello c', 'Hello d', 'Hello e', 'Hello f', 'Hello g', 'Hello h']; 1119e41f4b71Sopenharmony_ci } 1120e41f4b71Sopenharmony_ci} 1121e41f4b71Sopenharmony_ci 1122e41f4b71Sopenharmony_ci@Entry 1123e41f4b71Sopenharmony_ci@Component 1124e41f4b71Sopenharmony_cistruct MyComponent { 1125e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1126e41f4b71Sopenharmony_ci 1127e41f4b71Sopenharmony_ci aboutToAppear() { 1128e41f4b71Sopenharmony_ci this.data.init() 1129e41f4b71Sopenharmony_ci } 1130e41f4b71Sopenharmony_ci 1131e41f4b71Sopenharmony_ci build() { 1132e41f4b71Sopenharmony_ci Column() { 1133e41f4b71Sopenharmony_ci Text('Multi-Data Change') 1134e41f4b71Sopenharmony_ci .fontSize(10) 1135e41f4b71Sopenharmony_ci .backgroundColor(Color.Blue) 1136e41f4b71Sopenharmony_ci .fontColor(Color.White) 1137e41f4b71Sopenharmony_ci .borderRadius(50) 1138e41f4b71Sopenharmony_ci .padding(5) 1139e41f4b71Sopenharmony_ci .onClick(() => { 1140e41f4b71Sopenharmony_ci this.data.operateData(); 1141e41f4b71Sopenharmony_ci }) 1142e41f4b71Sopenharmony_ci List({ space: 3 }) { 1143e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1144e41f4b71Sopenharmony_ci ListItem() { 1145e41f4b71Sopenharmony_ci Row() { 1146e41f4b71Sopenharmony_ci Text(item).fontSize(35) 1147e41f4b71Sopenharmony_ci .onAppear(() => { 1148e41f4b71Sopenharmony_ci console.info("appear:" + item) 1149e41f4b71Sopenharmony_ci }) 1150e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1151e41f4b71Sopenharmony_ci } 1152e41f4b71Sopenharmony_ci 1153e41f4b71Sopenharmony_ci }, (item: string) => item + new Date().getTime()) 1154e41f4b71Sopenharmony_ci }.cachedCount(5) 1155e41f4b71Sopenharmony_ci } 1156e41f4b71Sopenharmony_ci } 1157e41f4b71Sopenharmony_ci} 1158e41f4b71Sopenharmony_ci``` 1159e41f4b71Sopenharmony_ci**Figure 9** Changing multiple data items in LazyForEach 1160e41f4b71Sopenharmony_ci 1161e41f4b71Sopenharmony_ci 1162e41f4b71Sopenharmony_ci 1163e41f4b71Sopenharmony_ciPay attention to the following when using the **onDatasetChange** API: 1164e41f4b71Sopenharmony_ci 1165e41f4b71Sopenharmony_ci1. The **onDatasetChange** API cannot be used together with other data operation APIs. 1166e41f4b71Sopenharmony_ci2. The input parameter of **onDatasetChange** is operations. The **index** of each operation is sourced from the original array. Therefore, the index in operations(input parameter of **onDatasetChange**) does not correspond exactly with the index in the operations on Datasource and is not negative. 1167e41f4b71Sopenharmony_ciThe first example clearly illustrates this point: 1168e41f4b71Sopenharmony_ci```ts 1169e41f4b71Sopenharmony_ci// Array before modification. 1170e41f4b71Sopenharmony_ci["Hello a","Hello b","Hello c","Hello d","Hello e","Hello f","Hello g","Hello h","Hello i","Hello j","Hello k","Hello l","Hello m","Hello n","Hello o","Hello p","Hello q","Hello r"] 1171e41f4b71Sopenharmony_ci//Array after modification. 1172e41f4b71Sopenharmony_ci["Hello a","Hello c","Hello d","Hello b","Hello g","Hello f","Hello e","Hello h","Hello 1","Hello 2","Hello i","Hello j","Hello m","Hello n","Hello o","Hello p","Hello q","Hello r"] 1173e41f4b71Sopenharmony_ci``` 1174e41f4b71Sopenharmony_ci**Hello b** is changed from item 2 to item 4. Therefore, the first **operation** is written in **{ type: DataOperationType.MOVE, index: { from: 1, to: 3 } }**. 1175e41f4b71Sopenharmony_ci**Hello e** whose index is 4 and **Hello g** whose index is 6 are exchanged in the original array. Therefore, the second **operation** is written in **{ type: DataOperationType.EXCHANGE, index: { start: 4, end: 6 } }**. 1176e41f4b71Sopenharmony_ci**Hello 1** and **Hello 2** are inserted after **Hello h** whose index is 7 in the original array. Therefore, the third **operation** is written in **{ type: DataOperationType.ADD, index: 8, count: 2 }**. 1177e41f4b71Sopenharmony_ci**Hello k** whose index is 10 and **Hello l** whose index is 11 are deleted in the original array. Therefore, the fourth **operation** is written in **{ type: DataOperationType.DELETE, index: 10, count: 2 }**. 1178e41f4b71Sopenharmony_ci 1179e41f4b71Sopenharmony_ci3. When **onDatasetChange** is called, the data can be operated only once for each index. If the data is operated multiple times, **LazyForEach** enables only the first operation to take effect. 1180e41f4b71Sopenharmony_ci4. In operations where you can specify keys on your own, **LazyForEach** does not call the key generator to obtain keys. As such, make sure the specified keys are correct. 1181e41f4b71Sopenharmony_ci5. If the API contains the **RELOAD** operation, other operations do not take effect. 1182e41f4b71Sopenharmony_ci 1183e41f4b71Sopenharmony_ci 1184e41f4b71Sopenharmony_ci 1185e41f4b71Sopenharmony_ci- ### Changing Data Subproperties 1186e41f4b71Sopenharmony_ci 1187e41f4b71Sopenharmony_ciWhen **LazyForEach** is used for UI re-renders, a child component needs to be destroyed and rebuilt when the data item changes. This may result in low re-render performance when the child component structure is complex. This is where @Observed and @ObjectLink come into picture. By providing in-depth observation, @Observed and @ObjectLink enable precise re-renders of only components that use the changed properties. You can select a re-render mode that better suits your needs. 1188e41f4b71Sopenharmony_ci 1189e41f4b71Sopenharmony_ci```ts 1190e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1191e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1192e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1193e41f4b71Sopenharmony_ci 1194e41f4b71Sopenharmony_ci public totalCount(): number { 1195e41f4b71Sopenharmony_ci return 0; 1196e41f4b71Sopenharmony_ci } 1197e41f4b71Sopenharmony_ci 1198e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1199e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1200e41f4b71Sopenharmony_ci } 1201e41f4b71Sopenharmony_ci 1202e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1203e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1204e41f4b71Sopenharmony_ci console.info('add listener'); 1205e41f4b71Sopenharmony_ci this.listeners.push(listener); 1206e41f4b71Sopenharmony_ci } 1207e41f4b71Sopenharmony_ci } 1208e41f4b71Sopenharmony_ci 1209e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1210e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1211e41f4b71Sopenharmony_ci if (pos >= 0) { 1212e41f4b71Sopenharmony_ci console.info('remove listener'); 1213e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1214e41f4b71Sopenharmony_ci } 1215e41f4b71Sopenharmony_ci } 1216e41f4b71Sopenharmony_ci 1217e41f4b71Sopenharmony_ci notifyDataReload(): void { 1218e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1219e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1220e41f4b71Sopenharmony_ci }) 1221e41f4b71Sopenharmony_ci } 1222e41f4b71Sopenharmony_ci 1223e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1224e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1225e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1226e41f4b71Sopenharmony_ci }) 1227e41f4b71Sopenharmony_ci } 1228e41f4b71Sopenharmony_ci 1229e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1230e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1231e41f4b71Sopenharmony_ci listener.onDataChange(index); 1232e41f4b71Sopenharmony_ci }) 1233e41f4b71Sopenharmony_ci } 1234e41f4b71Sopenharmony_ci 1235e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1236e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1237e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1238e41f4b71Sopenharmony_ci }) 1239e41f4b71Sopenharmony_ci } 1240e41f4b71Sopenharmony_ci 1241e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1242e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1243e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1244e41f4b71Sopenharmony_ci }) 1245e41f4b71Sopenharmony_ci } 1246e41f4b71Sopenharmony_ci} 1247e41f4b71Sopenharmony_ci 1248e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1249e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1250e41f4b71Sopenharmony_ci 1251e41f4b71Sopenharmony_ci public totalCount(): number { 1252e41f4b71Sopenharmony_ci return this.dataArray.length; 1253e41f4b71Sopenharmony_ci } 1254e41f4b71Sopenharmony_ci 1255e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1256e41f4b71Sopenharmony_ci return this.dataArray[index]; 1257e41f4b71Sopenharmony_ci } 1258e41f4b71Sopenharmony_ci 1259e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1260e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1261e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1262e41f4b71Sopenharmony_ci } 1263e41f4b71Sopenharmony_ci 1264e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1265e41f4b71Sopenharmony_ci this.dataArray.push(data); 1266e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1267e41f4b71Sopenharmony_ci } 1268e41f4b71Sopenharmony_ci} 1269e41f4b71Sopenharmony_ci 1270e41f4b71Sopenharmony_ci@Observed 1271e41f4b71Sopenharmony_ciclass StringData { 1272e41f4b71Sopenharmony_ci message: string; 1273e41f4b71Sopenharmony_ci constructor(message: string) { 1274e41f4b71Sopenharmony_ci this.message = message; 1275e41f4b71Sopenharmony_ci } 1276e41f4b71Sopenharmony_ci} 1277e41f4b71Sopenharmony_ci 1278e41f4b71Sopenharmony_ci@Entry 1279e41f4b71Sopenharmony_ci@Component 1280e41f4b71Sopenharmony_cistruct MyComponent { 1281e41f4b71Sopenharmony_ci private moved: number[] = []; 1282e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 1283e41f4b71Sopenharmony_ci 1284e41f4b71Sopenharmony_ci aboutToAppear() { 1285e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1286e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`)); 1287e41f4b71Sopenharmony_ci } 1288e41f4b71Sopenharmony_ci } 1289e41f4b71Sopenharmony_ci 1290e41f4b71Sopenharmony_ci build() { 1291e41f4b71Sopenharmony_ci List({ space: 3 }) { 1292e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1293e41f4b71Sopenharmony_ci ListItem() { 1294e41f4b71Sopenharmony_ci ChildComponent({data: item}) 1295e41f4b71Sopenharmony_ci } 1296e41f4b71Sopenharmony_ci .onClick(() => { 1297e41f4b71Sopenharmony_ci item.message += '0'; 1298e41f4b71Sopenharmony_ci }) 1299e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => index.toString()) 1300e41f4b71Sopenharmony_ci }.cachedCount(5) 1301e41f4b71Sopenharmony_ci } 1302e41f4b71Sopenharmony_ci} 1303e41f4b71Sopenharmony_ci 1304e41f4b71Sopenharmony_ci@Component 1305e41f4b71Sopenharmony_cistruct ChildComponent { 1306e41f4b71Sopenharmony_ci @ObjectLink data: StringData 1307e41f4b71Sopenharmony_ci build() { 1308e41f4b71Sopenharmony_ci Row() { 1309e41f4b71Sopenharmony_ci Text(this.data.message).fontSize(50) 1310e41f4b71Sopenharmony_ci .onAppear(() => { 1311e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message) 1312e41f4b71Sopenharmony_ci }) 1313e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1314e41f4b71Sopenharmony_ci } 1315e41f4b71Sopenharmony_ci} 1316e41f4b71Sopenharmony_ci``` 1317e41f4b71Sopenharmony_ci 1318e41f4b71Sopenharmony_ciWhen the child component of **LazyForEach** is clicked, **item.message** is changed. As re-rendering depends on the listening of the @ObjectLink decorated member variable of **ChildComponent** on its subproperties. In this case, the framework only re-renders **Text(this.data.message)** and does not rebuild the entire **ListItem** child component. 1319e41f4b71Sopenharmony_ci 1320e41f4b71Sopenharmony_ci**Figure 10** Changing data subproperties in LazyForEach 1321e41f4b71Sopenharmony_ci 1322e41f4b71Sopenharmony_ci 1323e41f4b71Sopenharmony_ci## Enabling Drag and Sort 1324e41f4b71Sopenharmony_ciIf **LazyForEach** is used in a list, and the **onMove** event is set, you can enable drag and sort for the list items. If an item changes the position after you drag and sort the data, the **onMove** event is triggered to report the original index and target index of the item. The data source needs to be modified in the **onMove** event based on the reported start index and target index. The **DataChangeListener** API does not need to be called to notify the data source change. 1325e41f4b71Sopenharmony_ci 1326e41f4b71Sopenharmony_ci```ts 1327e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1328e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1329e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1330e41f4b71Sopenharmony_ci 1331e41f4b71Sopenharmony_ci public totalCount(): number { 1332e41f4b71Sopenharmony_ci return 0; 1333e41f4b71Sopenharmony_ci } 1334e41f4b71Sopenharmony_ci 1335e41f4b71Sopenharmony_ci public getData(index: number): string { 1336e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1337e41f4b71Sopenharmony_ci } 1338e41f4b71Sopenharmony_ci 1339e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1340e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1341e41f4b71Sopenharmony_ci console.info('add listener'); 1342e41f4b71Sopenharmony_ci this.listeners.push(listener); 1343e41f4b71Sopenharmony_ci } 1344e41f4b71Sopenharmony_ci } 1345e41f4b71Sopenharmony_ci 1346e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1347e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1348e41f4b71Sopenharmony_ci if (pos >= 0) { 1349e41f4b71Sopenharmony_ci console.info('remove listener'); 1350e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1351e41f4b71Sopenharmony_ci } 1352e41f4b71Sopenharmony_ci } 1353e41f4b71Sopenharmony_ci 1354e41f4b71Sopenharmony_ci notifyDataReload(): void { 1355e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1356e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1357e41f4b71Sopenharmony_ci }) 1358e41f4b71Sopenharmony_ci } 1359e41f4b71Sopenharmony_ci 1360e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1361e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1362e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1363e41f4b71Sopenharmony_ci }) 1364e41f4b71Sopenharmony_ci } 1365e41f4b71Sopenharmony_ci 1366e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1367e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1368e41f4b71Sopenharmony_ci listener.onDataChange(index); 1369e41f4b71Sopenharmony_ci }) 1370e41f4b71Sopenharmony_ci } 1371e41f4b71Sopenharmony_ci 1372e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1373e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1374e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1375e41f4b71Sopenharmony_ci }) 1376e41f4b71Sopenharmony_ci } 1377e41f4b71Sopenharmony_ci 1378e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1379e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1380e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1381e41f4b71Sopenharmony_ci }) 1382e41f4b71Sopenharmony_ci } 1383e41f4b71Sopenharmony_ci} 1384e41f4b71Sopenharmony_ci 1385e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1386e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1387e41f4b71Sopenharmony_ci 1388e41f4b71Sopenharmony_ci public totalCount(): number { 1389e41f4b71Sopenharmony_ci return this.dataArray.length; 1390e41f4b71Sopenharmony_ci } 1391e41f4b71Sopenharmony_ci 1392e41f4b71Sopenharmony_ci public getData(index: number): string { 1393e41f4b71Sopenharmony_ci return this.dataArray[index]; 1394e41f4b71Sopenharmony_ci } 1395e41f4b71Sopenharmony_ci 1396e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1397e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1398e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1399e41f4b71Sopenharmony_ci } 1400e41f4b71Sopenharmony_ci 1401e41f4b71Sopenharmony_ci public moveDataWithoutNotify(from: number, to: number): void { 1402e41f4b71Sopenharmony_ci let tmp = this.dataArray.splice(from, 1); 1403e41f4b71Sopenharmony_ci this.dataArray.splice(to, 0, tmp[0]) 1404e41f4b71Sopenharmony_ci } 1405e41f4b71Sopenharmony_ci 1406e41f4b71Sopenharmony_ci public pushData(data: string): void { 1407e41f4b71Sopenharmony_ci this.dataArray.push(data); 1408e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1409e41f4b71Sopenharmony_ci } 1410e41f4b71Sopenharmony_ci 1411e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1412e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1413e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1414e41f4b71Sopenharmony_ci } 1415e41f4b71Sopenharmony_ci} 1416e41f4b71Sopenharmony_ci 1417e41f4b71Sopenharmony_ci@Entry 1418e41f4b71Sopenharmony_ci@Component 1419e41f4b71Sopenharmony_cistruct Parent { 1420e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1421e41f4b71Sopenharmony_ci 1422e41f4b71Sopenharmony_ci build() { 1423e41f4b71Sopenharmony_ci Row() { 1424e41f4b71Sopenharmony_ci List() { 1425e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 1426e41f4b71Sopenharmony_ci ListItem() { 1427e41f4b71Sopenharmony_ci Text(item.toString()) 1428e41f4b71Sopenharmony_ci .fontSize(16) 1429e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 1430e41f4b71Sopenharmony_ci .size({height: 100, width: "100%"}) 1431e41f4b71Sopenharmony_ci }.margin(10) 1432e41f4b71Sopenharmony_ci .borderRadius(10) 1433e41f4b71Sopenharmony_ci .backgroundColor("#FFFFFFFF") 1434e41f4b71Sopenharmony_ci }, (item: string) => item) 1435e41f4b71Sopenharmony_ci .onMove((from:number, to:number)=>{ 1436e41f4b71Sopenharmony_ci this.data.moveDataWithoutNotify(from, to) 1437e41f4b71Sopenharmony_ci }) 1438e41f4b71Sopenharmony_ci } 1439e41f4b71Sopenharmony_ci .width('100%') 1440e41f4b71Sopenharmony_ci .height('100%') 1441e41f4b71Sopenharmony_ci .backgroundColor("#FFDCDCDC") 1442e41f4b71Sopenharmony_ci } 1443e41f4b71Sopenharmony_ci } 1444e41f4b71Sopenharmony_ci aboutToAppear(): void { 1445e41f4b71Sopenharmony_ci for (let i = 0; i < 100; i++) { 1446e41f4b71Sopenharmony_ci this.data.pushData(i.toString()) 1447e41f4b71Sopenharmony_ci } 1448e41f4b71Sopenharmony_ci } 1449e41f4b71Sopenharmony_ci} 1450e41f4b71Sopenharmony_ci``` 1451e41f4b71Sopenharmony_ci 1452e41f4b71Sopenharmony_ci**Figure 11** Drag and sort in LazyForEach 1453e41f4b71Sopenharmony_ci 1454e41f4b71Sopenharmony_ci 1455e41f4b71Sopenharmony_ci## FAQs 1456e41f4b71Sopenharmony_ci 1457e41f4b71Sopenharmony_ci- ### Unexpected Rendering Result 1458e41f4b71Sopenharmony_ci 1459e41f4b71Sopenharmony_ci ```ts 1460e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1461e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1462e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1463e41f4b71Sopenharmony_ci 1464e41f4b71Sopenharmony_ci public totalCount(): number { 1465e41f4b71Sopenharmony_ci return 0; 1466e41f4b71Sopenharmony_ci } 1467e41f4b71Sopenharmony_ci 1468e41f4b71Sopenharmony_ci public getData(index: number): string { 1469e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1470e41f4b71Sopenharmony_ci } 1471e41f4b71Sopenharmony_ci 1472e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1473e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1474e41f4b71Sopenharmony_ci console.info('add listener'); 1475e41f4b71Sopenharmony_ci this.listeners.push(listener); 1476e41f4b71Sopenharmony_ci } 1477e41f4b71Sopenharmony_ci } 1478e41f4b71Sopenharmony_ci 1479e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1480e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1481e41f4b71Sopenharmony_ci if (pos >= 0) { 1482e41f4b71Sopenharmony_ci console.info('remove listener'); 1483e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1484e41f4b71Sopenharmony_ci } 1485e41f4b71Sopenharmony_ci } 1486e41f4b71Sopenharmony_ci 1487e41f4b71Sopenharmony_ci notifyDataReload(): void { 1488e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1489e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1490e41f4b71Sopenharmony_ci }) 1491e41f4b71Sopenharmony_ci } 1492e41f4b71Sopenharmony_ci 1493e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1494e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1495e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1496e41f4b71Sopenharmony_ci }) 1497e41f4b71Sopenharmony_ci } 1498e41f4b71Sopenharmony_ci 1499e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1500e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1501e41f4b71Sopenharmony_ci listener.onDataChange(index); 1502e41f4b71Sopenharmony_ci }) 1503e41f4b71Sopenharmony_ci } 1504e41f4b71Sopenharmony_ci 1505e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1506e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1507e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1508e41f4b71Sopenharmony_ci }) 1509e41f4b71Sopenharmony_ci } 1510e41f4b71Sopenharmony_ci 1511e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1512e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1513e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1514e41f4b71Sopenharmony_ci }) 1515e41f4b71Sopenharmony_ci } 1516e41f4b71Sopenharmony_ci } 1517e41f4b71Sopenharmony_ci 1518e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1519e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1520e41f4b71Sopenharmony_ci 1521e41f4b71Sopenharmony_ci public totalCount(): number { 1522e41f4b71Sopenharmony_ci return this.dataArray.length; 1523e41f4b71Sopenharmony_ci } 1524e41f4b71Sopenharmony_ci 1525e41f4b71Sopenharmony_ci public getData(index: number): string { 1526e41f4b71Sopenharmony_ci return this.dataArray[index]; 1527e41f4b71Sopenharmony_ci } 1528e41f4b71Sopenharmony_ci 1529e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1530e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1531e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1532e41f4b71Sopenharmony_ci } 1533e41f4b71Sopenharmony_ci 1534e41f4b71Sopenharmony_ci public pushData(data: string): void { 1535e41f4b71Sopenharmony_ci this.dataArray.push(data); 1536e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1537e41f4b71Sopenharmony_ci } 1538e41f4b71Sopenharmony_ci 1539e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1540e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1541e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1542e41f4b71Sopenharmony_ci } 1543e41f4b71Sopenharmony_ci } 1544e41f4b71Sopenharmony_ci 1545e41f4b71Sopenharmony_ci @Entry 1546e41f4b71Sopenharmony_ci @Component 1547e41f4b71Sopenharmony_ci struct MyComponent { 1548e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1549e41f4b71Sopenharmony_ci 1550e41f4b71Sopenharmony_ci aboutToAppear() { 1551e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1552e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 1553e41f4b71Sopenharmony_ci } 1554e41f4b71Sopenharmony_ci } 1555e41f4b71Sopenharmony_ci 1556e41f4b71Sopenharmony_ci build() { 1557e41f4b71Sopenharmony_ci List({ space: 3 }) { 1558e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1559e41f4b71Sopenharmony_ci ListItem() { 1560e41f4b71Sopenharmony_ci Row() { 1561e41f4b71Sopenharmony_ci Text(item).fontSize(50) 1562e41f4b71Sopenharmony_ci .onAppear(() => { 1563e41f4b71Sopenharmony_ci console.info("appear:" + item) 1564e41f4b71Sopenharmony_ci }) 1565e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1566e41f4b71Sopenharmony_ci } 1567e41f4b71Sopenharmony_ci .onClick(() => { 1568e41f4b71Sopenharmony_ci // Click to delete a child component. 1569e41f4b71Sopenharmony_ci this.data.deleteData(index); 1570e41f4b71Sopenharmony_ci }) 1571e41f4b71Sopenharmony_ci }, (item: string) => item) 1572e41f4b71Sopenharmony_ci }.cachedCount(5) 1573e41f4b71Sopenharmony_ci } 1574e41f4b71Sopenharmony_ci } 1575e41f4b71Sopenharmony_ci ``` 1576e41f4b71Sopenharmony_ci 1577e41f4b71Sopenharmony_ci **Figure 12** Unexpected data deletion by LazyForEach 1578e41f4b71Sopenharmony_ci  1579e41f4b71Sopenharmony_ci 1580e41f4b71Sopenharmony_ci When child components are clicked to be deleted, there may be cases where the deleted child component is not the one clicked. If this is the case, the indexes of data items are not updated correctly. In normal cases, after a child component is deleted, all data items following the data item of the child component should have their index decreased by 1. If these data items still use the original indexes, the indexes in **itemGenerator** do not change, resulting in the unexpected rendering result. 1581e41f4b71Sopenharmony_ci 1582e41f4b71Sopenharmony_ci The following shows the code snippet after optimization: 1583e41f4b71Sopenharmony_ci 1584e41f4b71Sopenharmony_ci ```ts 1585e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1586e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1587e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1588e41f4b71Sopenharmony_ci 1589e41f4b71Sopenharmony_ci public totalCount(): number { 1590e41f4b71Sopenharmony_ci return 0; 1591e41f4b71Sopenharmony_ci } 1592e41f4b71Sopenharmony_ci 1593e41f4b71Sopenharmony_ci public getData(index: number): string { 1594e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1595e41f4b71Sopenharmony_ci } 1596e41f4b71Sopenharmony_ci 1597e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1598e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1599e41f4b71Sopenharmony_ci console.info('add listener'); 1600e41f4b71Sopenharmony_ci this.listeners.push(listener); 1601e41f4b71Sopenharmony_ci } 1602e41f4b71Sopenharmony_ci } 1603e41f4b71Sopenharmony_ci 1604e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1605e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1606e41f4b71Sopenharmony_ci if (pos >= 0) { 1607e41f4b71Sopenharmony_ci console.info('remove listener'); 1608e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1609e41f4b71Sopenharmony_ci } 1610e41f4b71Sopenharmony_ci } 1611e41f4b71Sopenharmony_ci 1612e41f4b71Sopenharmony_ci notifyDataReload(): void { 1613e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1614e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1615e41f4b71Sopenharmony_ci }) 1616e41f4b71Sopenharmony_ci } 1617e41f4b71Sopenharmony_ci 1618e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1619e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1620e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1621e41f4b71Sopenharmony_ci }) 1622e41f4b71Sopenharmony_ci } 1623e41f4b71Sopenharmony_ci 1624e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1625e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1626e41f4b71Sopenharmony_ci listener.onDataChange(index); 1627e41f4b71Sopenharmony_ci }) 1628e41f4b71Sopenharmony_ci } 1629e41f4b71Sopenharmony_ci 1630e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1631e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1632e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1633e41f4b71Sopenharmony_ci }) 1634e41f4b71Sopenharmony_ci } 1635e41f4b71Sopenharmony_ci 1636e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1637e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1638e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1639e41f4b71Sopenharmony_ci }) 1640e41f4b71Sopenharmony_ci } 1641e41f4b71Sopenharmony_ci } 1642e41f4b71Sopenharmony_ci 1643e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1644e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1645e41f4b71Sopenharmony_ci 1646e41f4b71Sopenharmony_ci public totalCount(): number { 1647e41f4b71Sopenharmony_ci return this.dataArray.length; 1648e41f4b71Sopenharmony_ci } 1649e41f4b71Sopenharmony_ci 1650e41f4b71Sopenharmony_ci public getData(index: number): string { 1651e41f4b71Sopenharmony_ci return this.dataArray[index]; 1652e41f4b71Sopenharmony_ci } 1653e41f4b71Sopenharmony_ci 1654e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1655e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1656e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1657e41f4b71Sopenharmony_ci } 1658e41f4b71Sopenharmony_ci 1659e41f4b71Sopenharmony_ci public pushData(data: string): void { 1660e41f4b71Sopenharmony_ci this.dataArray.push(data); 1661e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1662e41f4b71Sopenharmony_ci } 1663e41f4b71Sopenharmony_ci 1664e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1665e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1666e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1667e41f4b71Sopenharmony_ci } 1668e41f4b71Sopenharmony_ci 1669e41f4b71Sopenharmony_ci public reloadData(): void { 1670e41f4b71Sopenharmony_ci this.notifyDataReload(); 1671e41f4b71Sopenharmony_ci } 1672e41f4b71Sopenharmony_ci } 1673e41f4b71Sopenharmony_ci 1674e41f4b71Sopenharmony_ci @Entry 1675e41f4b71Sopenharmony_ci @Component 1676e41f4b71Sopenharmony_ci struct MyComponent { 1677e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1678e41f4b71Sopenharmony_ci 1679e41f4b71Sopenharmony_ci aboutToAppear() { 1680e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1681e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 1682e41f4b71Sopenharmony_ci } 1683e41f4b71Sopenharmony_ci } 1684e41f4b71Sopenharmony_ci 1685e41f4b71Sopenharmony_ci build() { 1686e41f4b71Sopenharmony_ci List({ space: 3 }) { 1687e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1688e41f4b71Sopenharmony_ci ListItem() { 1689e41f4b71Sopenharmony_ci Row() { 1690e41f4b71Sopenharmony_ci Text(item).fontSize(50) 1691e41f4b71Sopenharmony_ci .onAppear(() => { 1692e41f4b71Sopenharmony_ci console.info("appear:" + item) 1693e41f4b71Sopenharmony_ci }) 1694e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1695e41f4b71Sopenharmony_ci } 1696e41f4b71Sopenharmony_ci .onClick(() => { 1697e41f4b71Sopenharmony_ci // Click to delete a child component. 1698e41f4b71Sopenharmony_ci this.data.deleteData(index); 1699e41f4b71Sopenharmony_ci // Reset the indexes of all child components. 1700e41f4b71Sopenharmony_ci this.data.reloadData(); 1701e41f4b71Sopenharmony_ci }) 1702e41f4b71Sopenharmony_ci }, (item: string, index: number) => item + index.toString()) 1703e41f4b71Sopenharmony_ci }.cachedCount(5) 1704e41f4b71Sopenharmony_ci } 1705e41f4b71Sopenharmony_ci } 1706e41f4b71Sopenharmony_ci ``` 1707e41f4b71Sopenharmony_ci 1708e41f4b71Sopenharmony_ci After a data item is deleted, the **reloadData** method is called to rebuild the subsequent data items to update the indexes. To gurantee that **reload** method will rebuild data items, we must make sure that new keys be generated for the data items. Here `item + index.toString()` gurantee that subsequent data items of the deleted one will be rebuit. If we replace key generator by `item + Data.now().toString()`, new keys will be generated for all remaining data items, so they all will be rebuilt. This way, effect is the same, but the performance is slightly inferior. 1709e41f4b71Sopenharmony_ci 1710e41f4b71Sopenharmony_ci **Figure 13** Fixing unexpected data deletion 1711e41f4b71Sopenharmony_ci  1712e41f4b71Sopenharmony_ci 1713e41f4b71Sopenharmony_ci- ### Image Flickering During Re-renders 1714e41f4b71Sopenharmony_ci 1715e41f4b71Sopenharmony_ci ```ts 1716e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1717e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1718e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1719e41f4b71Sopenharmony_ci 1720e41f4b71Sopenharmony_ci public totalCount(): number { 1721e41f4b71Sopenharmony_ci return 0; 1722e41f4b71Sopenharmony_ci } 1723e41f4b71Sopenharmony_ci 1724e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1725e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1726e41f4b71Sopenharmony_ci } 1727e41f4b71Sopenharmony_ci 1728e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1729e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1730e41f4b71Sopenharmony_ci console.info('add listener'); 1731e41f4b71Sopenharmony_ci this.listeners.push(listener); 1732e41f4b71Sopenharmony_ci } 1733e41f4b71Sopenharmony_ci } 1734e41f4b71Sopenharmony_ci 1735e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1736e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1737e41f4b71Sopenharmony_ci if (pos >= 0) { 1738e41f4b71Sopenharmony_ci console.info('remove listener'); 1739e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1740e41f4b71Sopenharmony_ci } 1741e41f4b71Sopenharmony_ci } 1742e41f4b71Sopenharmony_ci 1743e41f4b71Sopenharmony_ci notifyDataReload(): void { 1744e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1745e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1746e41f4b71Sopenharmony_ci }) 1747e41f4b71Sopenharmony_ci } 1748e41f4b71Sopenharmony_ci 1749e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1750e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1751e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1752e41f4b71Sopenharmony_ci }) 1753e41f4b71Sopenharmony_ci } 1754e41f4b71Sopenharmony_ci 1755e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1756e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1757e41f4b71Sopenharmony_ci listener.onDataChange(index); 1758e41f4b71Sopenharmony_ci }) 1759e41f4b71Sopenharmony_ci } 1760e41f4b71Sopenharmony_ci 1761e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1762e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1763e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1764e41f4b71Sopenharmony_ci }) 1765e41f4b71Sopenharmony_ci } 1766e41f4b71Sopenharmony_ci 1767e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1768e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1769e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1770e41f4b71Sopenharmony_ci }) 1771e41f4b71Sopenharmony_ci } 1772e41f4b71Sopenharmony_ci } 1773e41f4b71Sopenharmony_ci 1774e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1775e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1776e41f4b71Sopenharmony_ci 1777e41f4b71Sopenharmony_ci public totalCount(): number { 1778e41f4b71Sopenharmony_ci return this.dataArray.length; 1779e41f4b71Sopenharmony_ci } 1780e41f4b71Sopenharmony_ci 1781e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1782e41f4b71Sopenharmony_ci return this.dataArray[index]; 1783e41f4b71Sopenharmony_ci } 1784e41f4b71Sopenharmony_ci 1785e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1786e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1787e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1788e41f4b71Sopenharmony_ci } 1789e41f4b71Sopenharmony_ci 1790e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1791e41f4b71Sopenharmony_ci this.dataArray.push(data); 1792e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1793e41f4b71Sopenharmony_ci } 1794e41f4b71Sopenharmony_ci 1795e41f4b71Sopenharmony_ci public reloadData(): void { 1796e41f4b71Sopenharmony_ci this.notifyDataReload(); 1797e41f4b71Sopenharmony_ci } 1798e41f4b71Sopenharmony_ci } 1799e41f4b71Sopenharmony_ci 1800e41f4b71Sopenharmony_ci class StringData { 1801e41f4b71Sopenharmony_ci message: string; 1802e41f4b71Sopenharmony_ci imgSrc: Resource; 1803e41f4b71Sopenharmony_ci constructor(message: string, imgSrc: Resource) { 1804e41f4b71Sopenharmony_ci this.message = message; 1805e41f4b71Sopenharmony_ci this.imgSrc = imgSrc; 1806e41f4b71Sopenharmony_ci } 1807e41f4b71Sopenharmony_ci } 1808e41f4b71Sopenharmony_ci 1809e41f4b71Sopenharmony_ci @Entry 1810e41f4b71Sopenharmony_ci @Component 1811e41f4b71Sopenharmony_ci struct MyComponent { 1812e41f4b71Sopenharmony_ci private moved: number[] = []; 1813e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1814e41f4b71Sopenharmony_ci 1815e41f4b71Sopenharmony_ci aboutToAppear() { 1816e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1817e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.img'))); 1818e41f4b71Sopenharmony_ci } 1819e41f4b71Sopenharmony_ci } 1820e41f4b71Sopenharmony_ci 1821e41f4b71Sopenharmony_ci build() { 1822e41f4b71Sopenharmony_ci List({ space: 3 }) { 1823e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1824e41f4b71Sopenharmony_ci ListItem() { 1825e41f4b71Sopenharmony_ci Column() { 1826e41f4b71Sopenharmony_ci Text(item.message).fontSize(50) 1827e41f4b71Sopenharmony_ci .onAppear(() => { 1828e41f4b71Sopenharmony_ci console.info("appear:" + item.message) 1829e41f4b71Sopenharmony_ci }) 1830e41f4b71Sopenharmony_ci Image(item.imgSrc) 1831e41f4b71Sopenharmony_ci .width(500) 1832e41f4b71Sopenharmony_ci .height(200) 1833e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1834e41f4b71Sopenharmony_ci } 1835e41f4b71Sopenharmony_ci .onClick(() => { 1836e41f4b71Sopenharmony_ci item.message += '00'; 1837e41f4b71Sopenharmony_ci this.data.reloadData(); 1838e41f4b71Sopenharmony_ci }) 1839e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item)) 1840e41f4b71Sopenharmony_ci }.cachedCount(5) 1841e41f4b71Sopenharmony_ci } 1842e41f4b71Sopenharmony_ci } 1843e41f4b71Sopenharmony_ci ``` 1844e41f4b71Sopenharmony_ci 1845e41f4b71Sopenharmony_ci **Figure 14** Unwanted image flickering with LazyForEach 1846e41f4b71Sopenharmony_ci  1847e41f4b71Sopenharmony_ci 1848e41f4b71Sopenharmony_ci In the example, when a list item is clicked, only the **message** property of the item is changed. Yet, along with the text change comes the unwanted image flickering. This is because, with the **LazyForEach** update mechanism, the entire list item is rebuilt. As the **Image** component is updated asynchronously, flickering occurs. To address this issue, use @ObjectLink and @Observed so that only the **Text** component that uses the **item.message** property is re-rendered. 1849e41f4b71Sopenharmony_ci 1850e41f4b71Sopenharmony_ci The following shows the code snippet after optimization: 1851e41f4b71Sopenharmony_ci 1852e41f4b71Sopenharmony_ci ```ts 1853e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1854e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1855e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1856e41f4b71Sopenharmony_ci 1857e41f4b71Sopenharmony_ci public totalCount(): number { 1858e41f4b71Sopenharmony_ci return 0; 1859e41f4b71Sopenharmony_ci } 1860e41f4b71Sopenharmony_ci 1861e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1862e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1863e41f4b71Sopenharmony_ci } 1864e41f4b71Sopenharmony_ci 1865e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1866e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1867e41f4b71Sopenharmony_ci console.info('add listener'); 1868e41f4b71Sopenharmony_ci this.listeners.push(listener); 1869e41f4b71Sopenharmony_ci } 1870e41f4b71Sopenharmony_ci } 1871e41f4b71Sopenharmony_ci 1872e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1873e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1874e41f4b71Sopenharmony_ci if (pos >= 0) { 1875e41f4b71Sopenharmony_ci console.info('remove listener'); 1876e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1877e41f4b71Sopenharmony_ci } 1878e41f4b71Sopenharmony_ci } 1879e41f4b71Sopenharmony_ci 1880e41f4b71Sopenharmony_ci notifyDataReload(): void { 1881e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1882e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1883e41f4b71Sopenharmony_ci }) 1884e41f4b71Sopenharmony_ci } 1885e41f4b71Sopenharmony_ci 1886e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1887e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1888e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1889e41f4b71Sopenharmony_ci }) 1890e41f4b71Sopenharmony_ci } 1891e41f4b71Sopenharmony_ci 1892e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1893e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1894e41f4b71Sopenharmony_ci listener.onDataChange(index); 1895e41f4b71Sopenharmony_ci }) 1896e41f4b71Sopenharmony_ci } 1897e41f4b71Sopenharmony_ci 1898e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1899e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1900e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1901e41f4b71Sopenharmony_ci }) 1902e41f4b71Sopenharmony_ci } 1903e41f4b71Sopenharmony_ci 1904e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1905e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1906e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1907e41f4b71Sopenharmony_ci }) 1908e41f4b71Sopenharmony_ci } 1909e41f4b71Sopenharmony_ci } 1910e41f4b71Sopenharmony_ci 1911e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1912e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1913e41f4b71Sopenharmony_ci 1914e41f4b71Sopenharmony_ci public totalCount(): number { 1915e41f4b71Sopenharmony_ci return this.dataArray.length; 1916e41f4b71Sopenharmony_ci } 1917e41f4b71Sopenharmony_ci 1918e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1919e41f4b71Sopenharmony_ci return this.dataArray[index]; 1920e41f4b71Sopenharmony_ci } 1921e41f4b71Sopenharmony_ci 1922e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1923e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1924e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1925e41f4b71Sopenharmony_ci } 1926e41f4b71Sopenharmony_ci 1927e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1928e41f4b71Sopenharmony_ci this.dataArray.push(data); 1929e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1930e41f4b71Sopenharmony_ci } 1931e41f4b71Sopenharmony_ci } 1932e41f4b71Sopenharmony_ci 1933e41f4b71Sopenharmony_ci @Observed 1934e41f4b71Sopenharmony_ci class StringData { 1935e41f4b71Sopenharmony_ci message: string; 1936e41f4b71Sopenharmony_ci imgSrc: Resource; 1937e41f4b71Sopenharmony_ci constructor(message: string, imgSrc: Resource) { 1938e41f4b71Sopenharmony_ci this.message = message; 1939e41f4b71Sopenharmony_ci this.imgSrc = imgSrc; 1940e41f4b71Sopenharmony_ci } 1941e41f4b71Sopenharmony_ci } 1942e41f4b71Sopenharmony_ci 1943e41f4b71Sopenharmony_ci @Entry 1944e41f4b71Sopenharmony_ci @Component 1945e41f4b71Sopenharmony_ci struct MyComponent { 1946e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 1947e41f4b71Sopenharmony_ci 1948e41f4b71Sopenharmony_ci aboutToAppear() { 1949e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1950e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.img'))); 1951e41f4b71Sopenharmony_ci } 1952e41f4b71Sopenharmony_ci } 1953e41f4b71Sopenharmony_ci 1954e41f4b71Sopenharmony_ci build() { 1955e41f4b71Sopenharmony_ci List({ space: 3 }) { 1956e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1957e41f4b71Sopenharmony_ci ListItem() { 1958e41f4b71Sopenharmony_ci ChildComponent({data: item}) 1959e41f4b71Sopenharmony_ci } 1960e41f4b71Sopenharmony_ci .onClick(() => { 1961e41f4b71Sopenharmony_ci item.message += '0'; 1962e41f4b71Sopenharmony_ci }) 1963e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => index.toString()) 1964e41f4b71Sopenharmony_ci }.cachedCount(5) 1965e41f4b71Sopenharmony_ci } 1966e41f4b71Sopenharmony_ci } 1967e41f4b71Sopenharmony_ci 1968e41f4b71Sopenharmony_ci @Component 1969e41f4b71Sopenharmony_ci struct ChildComponent { 1970e41f4b71Sopenharmony_ci @ObjectLink data: StringData 1971e41f4b71Sopenharmony_ci build() { 1972e41f4b71Sopenharmony_ci Column() { 1973e41f4b71Sopenharmony_ci Text(this.data.message).fontSize(50) 1974e41f4b71Sopenharmony_ci .onAppear(() => { 1975e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message) 1976e41f4b71Sopenharmony_ci }) 1977e41f4b71Sopenharmony_ci Image(this.data.imgSrc) 1978e41f4b71Sopenharmony_ci .width(500) 1979e41f4b71Sopenharmony_ci .height(200) 1980e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1981e41f4b71Sopenharmony_ci } 1982e41f4b71Sopenharmony_ci } 1983e41f4b71Sopenharmony_ci ``` 1984e41f4b71Sopenharmony_ci 1985e41f4b71Sopenharmony_ci **Figure 15** Fixing unwanted image flickering 1986e41f4b71Sopenharmony_ci  1987e41f4b71Sopenharmony_ci 1988e41f4b71Sopenharmony_ci- ### UI Not Re-rendered When @ObjectLink Property Is Changed 1989e41f4b71Sopenharmony_ci 1990e41f4b71Sopenharmony_ci ```ts 1991e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1992e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1993e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1994e41f4b71Sopenharmony_ci 1995e41f4b71Sopenharmony_ci public totalCount(): number { 1996e41f4b71Sopenharmony_ci return 0; 1997e41f4b71Sopenharmony_ci } 1998e41f4b71Sopenharmony_ci 1999e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2000e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2001e41f4b71Sopenharmony_ci } 2002e41f4b71Sopenharmony_ci 2003e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2004e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2005e41f4b71Sopenharmony_ci console.info('add listener'); 2006e41f4b71Sopenharmony_ci this.listeners.push(listener); 2007e41f4b71Sopenharmony_ci } 2008e41f4b71Sopenharmony_ci } 2009e41f4b71Sopenharmony_ci 2010e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2011e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2012e41f4b71Sopenharmony_ci if (pos >= 0) { 2013e41f4b71Sopenharmony_ci console.info('remove listener'); 2014e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2015e41f4b71Sopenharmony_ci } 2016e41f4b71Sopenharmony_ci } 2017e41f4b71Sopenharmony_ci 2018e41f4b71Sopenharmony_ci notifyDataReload(): void { 2019e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2020e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2021e41f4b71Sopenharmony_ci }) 2022e41f4b71Sopenharmony_ci } 2023e41f4b71Sopenharmony_ci 2024e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2025e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2026e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2027e41f4b71Sopenharmony_ci }) 2028e41f4b71Sopenharmony_ci } 2029e41f4b71Sopenharmony_ci 2030e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2031e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2032e41f4b71Sopenharmony_ci listener.onDataChange(index); 2033e41f4b71Sopenharmony_ci }) 2034e41f4b71Sopenharmony_ci } 2035e41f4b71Sopenharmony_ci 2036e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2037e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2038e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2039e41f4b71Sopenharmony_ci }) 2040e41f4b71Sopenharmony_ci } 2041e41f4b71Sopenharmony_ci 2042e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2043e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2044e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2045e41f4b71Sopenharmony_ci }) 2046e41f4b71Sopenharmony_ci } 2047e41f4b71Sopenharmony_ci } 2048e41f4b71Sopenharmony_ci 2049e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 2050e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 2051e41f4b71Sopenharmony_ci 2052e41f4b71Sopenharmony_ci public totalCount(): number { 2053e41f4b71Sopenharmony_ci return this.dataArray.length; 2054e41f4b71Sopenharmony_ci } 2055e41f4b71Sopenharmony_ci 2056e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2057e41f4b71Sopenharmony_ci return this.dataArray[index]; 2058e41f4b71Sopenharmony_ci } 2059e41f4b71Sopenharmony_ci 2060e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 2061e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2062e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2063e41f4b71Sopenharmony_ci } 2064e41f4b71Sopenharmony_ci 2065e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 2066e41f4b71Sopenharmony_ci this.dataArray.push(data); 2067e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2068e41f4b71Sopenharmony_ci } 2069e41f4b71Sopenharmony_ci } 2070e41f4b71Sopenharmony_ci 2071e41f4b71Sopenharmony_ci @Observed 2072e41f4b71Sopenharmony_ci class StringData { 2073e41f4b71Sopenharmony_ci message: NestedString; 2074e41f4b71Sopenharmony_ci constructor(message: NestedString) { 2075e41f4b71Sopenharmony_ci this.message = message; 2076e41f4b71Sopenharmony_ci } 2077e41f4b71Sopenharmony_ci } 2078e41f4b71Sopenharmony_ci 2079e41f4b71Sopenharmony_ci @Observed 2080e41f4b71Sopenharmony_ci class NestedString { 2081e41f4b71Sopenharmony_ci message: string; 2082e41f4b71Sopenharmony_ci constructor(message: string) { 2083e41f4b71Sopenharmony_ci this.message = message; 2084e41f4b71Sopenharmony_ci } 2085e41f4b71Sopenharmony_ci } 2086e41f4b71Sopenharmony_ci 2087e41f4b71Sopenharmony_ci @Entry 2088e41f4b71Sopenharmony_ci @Component 2089e41f4b71Sopenharmony_ci struct MyComponent { 2090e41f4b71Sopenharmony_ci private moved: number[] = []; 2091e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 2092e41f4b71Sopenharmony_ci 2093e41f4b71Sopenharmony_ci aboutToAppear() { 2094e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 2095e41f4b71Sopenharmony_ci this.data.pushData(new StringData(new NestedString(`Hello ${i}`))); 2096e41f4b71Sopenharmony_ci } 2097e41f4b71Sopenharmony_ci } 2098e41f4b71Sopenharmony_ci 2099e41f4b71Sopenharmony_ci build() { 2100e41f4b71Sopenharmony_ci List({ space: 3 }) { 2101e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 2102e41f4b71Sopenharmony_ci ListItem() { 2103e41f4b71Sopenharmony_ci ChildComponent({data: item}) 2104e41f4b71Sopenharmony_ci } 2105e41f4b71Sopenharmony_ci .onClick(() => { 2106e41f4b71Sopenharmony_ci item.message.message += '0'; 2107e41f4b71Sopenharmony_ci }) 2108e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item) + index.toString()) 2109e41f4b71Sopenharmony_ci }.cachedCount(5) 2110e41f4b71Sopenharmony_ci } 2111e41f4b71Sopenharmony_ci } 2112e41f4b71Sopenharmony_ci 2113e41f4b71Sopenharmony_ci @Component 2114e41f4b71Sopenharmony_ci struct ChildComponent { 2115e41f4b71Sopenharmony_ci @ObjectLink data: StringData 2116e41f4b71Sopenharmony_ci build() { 2117e41f4b71Sopenharmony_ci Row() { 2118e41f4b71Sopenharmony_ci Text(this.data.message.message).fontSize(50) 2119e41f4b71Sopenharmony_ci .onAppear(() => { 2120e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message.message) 2121e41f4b71Sopenharmony_ci }) 2122e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2123e41f4b71Sopenharmony_ci } 2124e41f4b71Sopenharmony_ci } 2125e41f4b71Sopenharmony_ci ``` 2126e41f4b71Sopenharmony_ci 2127e41f4b71Sopenharmony_ci **Figure 16** UI not re-rendered when @ObjectLink property is changed 2128e41f4b71Sopenharmony_ci  2129e41f4b71Sopenharmony_ci 2130e41f4b71Sopenharmony_ci The member variable decorated by @ObjectLink can observe only changes of its sub-properties, not changes of nested properties. Therefore, to instruct a component to re-render, we need to change the component sub-properties. For details, see [\@Observed and \@ObjectLink Decorators](./arkts-observed-and-objectlink.md). 2131e41f4b71Sopenharmony_ci 2132e41f4b71Sopenharmony_ci The following shows the code snippet after optimization: 2133e41f4b71Sopenharmony_ci 2134e41f4b71Sopenharmony_ci ```ts 2135e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 2136e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2137e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 2138e41f4b71Sopenharmony_ci 2139e41f4b71Sopenharmony_ci public totalCount(): number { 2140e41f4b71Sopenharmony_ci return 0; 2141e41f4b71Sopenharmony_ci } 2142e41f4b71Sopenharmony_ci 2143e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2144e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2145e41f4b71Sopenharmony_ci } 2146e41f4b71Sopenharmony_ci 2147e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2148e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2149e41f4b71Sopenharmony_ci console.info('add listener'); 2150e41f4b71Sopenharmony_ci this.listeners.push(listener); 2151e41f4b71Sopenharmony_ci } 2152e41f4b71Sopenharmony_ci } 2153e41f4b71Sopenharmony_ci 2154e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2155e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2156e41f4b71Sopenharmony_ci if (pos >= 0) { 2157e41f4b71Sopenharmony_ci console.info('remove listener'); 2158e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2159e41f4b71Sopenharmony_ci } 2160e41f4b71Sopenharmony_ci } 2161e41f4b71Sopenharmony_ci 2162e41f4b71Sopenharmony_ci notifyDataReload(): void { 2163e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2164e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2165e41f4b71Sopenharmony_ci }) 2166e41f4b71Sopenharmony_ci } 2167e41f4b71Sopenharmony_ci 2168e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2169e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2170e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2171e41f4b71Sopenharmony_ci }) 2172e41f4b71Sopenharmony_ci } 2173e41f4b71Sopenharmony_ci 2174e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2175e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2176e41f4b71Sopenharmony_ci listener.onDataChange(index); 2177e41f4b71Sopenharmony_ci }) 2178e41f4b71Sopenharmony_ci } 2179e41f4b71Sopenharmony_ci 2180e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2181e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2182e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2183e41f4b71Sopenharmony_ci }) 2184e41f4b71Sopenharmony_ci } 2185e41f4b71Sopenharmony_ci 2186e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2187e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2188e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2189e41f4b71Sopenharmony_ci }) 2190e41f4b71Sopenharmony_ci } 2191e41f4b71Sopenharmony_ci } 2192e41f4b71Sopenharmony_ci 2193e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 2194e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 2195e41f4b71Sopenharmony_ci 2196e41f4b71Sopenharmony_ci public totalCount(): number { 2197e41f4b71Sopenharmony_ci return this.dataArray.length; 2198e41f4b71Sopenharmony_ci } 2199e41f4b71Sopenharmony_ci 2200e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2201e41f4b71Sopenharmony_ci return this.dataArray[index]; 2202e41f4b71Sopenharmony_ci } 2203e41f4b71Sopenharmony_ci 2204e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 2205e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2206e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2207e41f4b71Sopenharmony_ci } 2208e41f4b71Sopenharmony_ci 2209e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 2210e41f4b71Sopenharmony_ci this.dataArray.push(data); 2211e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2212e41f4b71Sopenharmony_ci } 2213e41f4b71Sopenharmony_ci } 2214e41f4b71Sopenharmony_ci 2215e41f4b71Sopenharmony_ci @Observed 2216e41f4b71Sopenharmony_ci class StringData { 2217e41f4b71Sopenharmony_ci message: NestedString; 2218e41f4b71Sopenharmony_ci constructor(message: NestedString) { 2219e41f4b71Sopenharmony_ci this.message = message; 2220e41f4b71Sopenharmony_ci } 2221e41f4b71Sopenharmony_ci } 2222e41f4b71Sopenharmony_ci 2223e41f4b71Sopenharmony_ci @Observed 2224e41f4b71Sopenharmony_ci class NestedString { 2225e41f4b71Sopenharmony_ci message: string; 2226e41f4b71Sopenharmony_ci constructor(message: string) { 2227e41f4b71Sopenharmony_ci this.message = message; 2228e41f4b71Sopenharmony_ci } 2229e41f4b71Sopenharmony_ci } 2230e41f4b71Sopenharmony_ci 2231e41f4b71Sopenharmony_ci @Entry 2232e41f4b71Sopenharmony_ci @Component 2233e41f4b71Sopenharmony_ci struct MyComponent { 2234e41f4b71Sopenharmony_ci private moved: number[] = []; 2235e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 2236e41f4b71Sopenharmony_ci 2237e41f4b71Sopenharmony_ci aboutToAppear() { 2238e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 2239e41f4b71Sopenharmony_ci this.data.pushData(new StringData(new NestedString(`Hello ${i}`))); 2240e41f4b71Sopenharmony_ci } 2241e41f4b71Sopenharmony_ci } 2242e41f4b71Sopenharmony_ci 2243e41f4b71Sopenharmony_ci build() { 2244e41f4b71Sopenharmony_ci List({ space: 3 }) { 2245e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 2246e41f4b71Sopenharmony_ci ListItem() { 2247e41f4b71Sopenharmony_ci ChildComponent({data: item}) 2248e41f4b71Sopenharmony_ci } 2249e41f4b71Sopenharmony_ci .onClick(() => { 2250e41f4b71Sopenharmony_ci item.message = new NestedString(item.message.message + '0'); 2251e41f4b71Sopenharmony_ci }) 2252e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item) + index.toString()) 2253e41f4b71Sopenharmony_ci }.cachedCount(5) 2254e41f4b71Sopenharmony_ci } 2255e41f4b71Sopenharmony_ci } 2256e41f4b71Sopenharmony_ci 2257e41f4b71Sopenharmony_ci @Component 2258e41f4b71Sopenharmony_ci struct ChildComponent { 2259e41f4b71Sopenharmony_ci @ObjectLink data: StringData 2260e41f4b71Sopenharmony_ci build() { 2261e41f4b71Sopenharmony_ci Row() { 2262e41f4b71Sopenharmony_ci Text(this.data.message.message).fontSize(50) 2263e41f4b71Sopenharmony_ci .onAppear(() => { 2264e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message.message) 2265e41f4b71Sopenharmony_ci }) 2266e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2267e41f4b71Sopenharmony_ci } 2268e41f4b71Sopenharmony_ci } 2269e41f4b71Sopenharmony_ci ``` 2270e41f4b71Sopenharmony_ci 2271e41f4b71Sopenharmony_ci **Figure 17** Fixing the UI-not-re-rendered issue 2272e41f4b71Sopenharmony_ci  2273e41f4b71Sopenharmony_ci 2274e41f4b71Sopenharmony_ci- ### Screen Flickering 2275e41f4b71Sopenharmony_ciList has an **onScrollIndex** callback function. When **onDataReloaded** is called in **onScrollIndex**, there is a risk of screen flickering. 2276e41f4b71Sopenharmony_ci 2277e41f4b71Sopenharmony_ci```ts 2278e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 2279e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2280e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 2281e41f4b71Sopenharmony_ci 2282e41f4b71Sopenharmony_ci public totalCount(): number { 2283e41f4b71Sopenharmony_ci return 0; 2284e41f4b71Sopenharmony_ci } 2285e41f4b71Sopenharmony_ci 2286e41f4b71Sopenharmony_ci public getData(index: number): string { 2287e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2288e41f4b71Sopenharmony_ci } 2289e41f4b71Sopenharmony_ci 2290e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2291e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2292e41f4b71Sopenharmony_ci console.info('add listener'); 2293e41f4b71Sopenharmony_ci this.listeners.push(listener); 2294e41f4b71Sopenharmony_ci } 2295e41f4b71Sopenharmony_ci } 2296e41f4b71Sopenharmony_ci 2297e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2298e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2299e41f4b71Sopenharmony_ci if (pos >= 0) { 2300e41f4b71Sopenharmony_ci console.info('remove listener'); 2301e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2302e41f4b71Sopenharmony_ci } 2303e41f4b71Sopenharmony_ci } 2304e41f4b71Sopenharmony_ci 2305e41f4b71Sopenharmony_ci notifyDataReload(): void { 2306e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2307e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2308e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.RELOAD}]); 2309e41f4b71Sopenharmony_ci }) 2310e41f4b71Sopenharmony_ci } 2311e41f4b71Sopenharmony_ci 2312e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2313e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2314e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2315e41f4b71Sopenharmony_ci }) 2316e41f4b71Sopenharmony_ci } 2317e41f4b71Sopenharmony_ci 2318e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2319e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2320e41f4b71Sopenharmony_ci listener.onDataChange(index); 2321e41f4b71Sopenharmony_ci }) 2322e41f4b71Sopenharmony_ci } 2323e41f4b71Sopenharmony_ci 2324e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2325e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2326e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2327e41f4b71Sopenharmony_ci }) 2328e41f4b71Sopenharmony_ci } 2329e41f4b71Sopenharmony_ci 2330e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2331e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2332e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2333e41f4b71Sopenharmony_ci }) 2334e41f4b71Sopenharmony_ci } 2335e41f4b71Sopenharmony_ci 2336e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]):void{ 2337e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2338e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 2339e41f4b71Sopenharmony_ci }) 2340e41f4b71Sopenharmony_ci } 2341e41f4b71Sopenharmony_ci} 2342e41f4b71Sopenharmony_ci 2343e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 2344e41f4b71Sopenharmony_ci private dataArray: string[] = []; 2345e41f4b71Sopenharmony_ci 2346e41f4b71Sopenharmony_ci public totalCount(): number { 2347e41f4b71Sopenharmony_ci return this.dataArray.length; 2348e41f4b71Sopenharmony_ci } 2349e41f4b71Sopenharmony_ci 2350e41f4b71Sopenharmony_ci public getData(index: number): string { 2351e41f4b71Sopenharmony_ci return this.dataArray[index]; 2352e41f4b71Sopenharmony_ci } 2353e41f4b71Sopenharmony_ci 2354e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 2355e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2356e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2357e41f4b71Sopenharmony_ci } 2358e41f4b71Sopenharmony_ci 2359e41f4b71Sopenharmony_ci public pushData(data: string): void { 2360e41f4b71Sopenharmony_ci this.dataArray.push(data); 2361e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2362e41f4b71Sopenharmony_ci } 2363e41f4b71Sopenharmony_ci 2364e41f4b71Sopenharmony_ci public deleteData(index: number): void { 2365e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 2366e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 2367e41f4b71Sopenharmony_ci } 2368e41f4b71Sopenharmony_ci 2369e41f4b71Sopenharmony_ci public changeData(index: number): void { 2370e41f4b71Sopenharmony_ci this.notifyDataChange(index); 2371e41f4b71Sopenharmony_ci } 2372e41f4b71Sopenharmony_ci 2373e41f4b71Sopenharmony_ci operateData():void { 2374e41f4b71Sopenharmony_ci const totalCount = this.dataArray.length; 2375e41f4b71Sopenharmony_ci const batch=5; 2376e41f4b71Sopenharmony_ci for (let i = totalCount; i < totalCount + batch; i++) { 2377e41f4b71Sopenharmony_ci this.dataArray.push(`Hello ${i}`) 2378e41f4b71Sopenharmony_ci } 2379e41f4b71Sopenharmony_ci this.notifyDataReload(); 2380e41f4b71Sopenharmony_ci } 2381e41f4b71Sopenharmony_ci} 2382e41f4b71Sopenharmony_ci 2383e41f4b71Sopenharmony_ci@Entry 2384e41f4b71Sopenharmony_ci@Component 2385e41f4b71Sopenharmony_cistruct MyComponent { 2386e41f4b71Sopenharmony_ci private moved: number[] = []; 2387e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 2388e41f4b71Sopenharmony_ci 2389e41f4b71Sopenharmony_ci aboutToAppear() { 2390e41f4b71Sopenharmony_ci for (let i = 0; i <= 10; i++) { 2391e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 2392e41f4b71Sopenharmony_ci } 2393e41f4b71Sopenharmony_ci } 2394e41f4b71Sopenharmony_ci 2395e41f4b71Sopenharmony_ci build() { 2396e41f4b71Sopenharmony_ci List({ space: 3 }) { 2397e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 2398e41f4b71Sopenharmony_ci ListItem() { 2399e41f4b71Sopenharmony_ci Row() { 2400e41f4b71Sopenharmony_ci Text(item) 2401e41f4b71Sopenharmony_ci .width('100%') 2402e41f4b71Sopenharmony_ci .height(80) 2403e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 2404e41f4b71Sopenharmony_ci .onAppear(() => { 2405e41f4b71Sopenharmony_ci console.info("appear:" + item) 2406e41f4b71Sopenharmony_ci }) 2407e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2408e41f4b71Sopenharmony_ci } 2409e41f4b71Sopenharmony_ci }, (item: string) => item) 2410e41f4b71Sopenharmony_ci }.cachedCount(10) 2411e41f4b71Sopenharmony_ci .onScrollIndex((start, end, center) => { 2412e41f4b71Sopenharmony_ci if (end === this.data.totalCount() - 1) { 2413e41f4b71Sopenharmony_ci console.log('scroll to end') 2414e41f4b71Sopenharmony_ci this.data.operateData(); 2415e41f4b71Sopenharmony_ci } 2416e41f4b71Sopenharmony_ci }) 2417e41f4b71Sopenharmony_ci } 2418e41f4b71Sopenharmony_ci} 2419e41f4b71Sopenharmony_ci``` 2420e41f4b71Sopenharmony_ci 2421e41f4b71Sopenharmony_ciWhen **List** is scrolled to the bottom, screen flicks like the following. 2422e41f4b71Sopenharmony_ci 2423e41f4b71Sopenharmony_ci 2424e41f4b71Sopenharmony_ciReplacing **onDataReloaded** by **onDatasetChange** cannot only fix this issue but also improves load performance. 2425e41f4b71Sopenharmony_ci 2426e41f4b71Sopenharmony_ci```ts 2427e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 2428e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2429e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 2430e41f4b71Sopenharmony_ci 2431e41f4b71Sopenharmony_ci public totalCount(): number { 2432e41f4b71Sopenharmony_ci return 0; 2433e41f4b71Sopenharmony_ci } 2434e41f4b71Sopenharmony_ci 2435e41f4b71Sopenharmony_ci public getData(index: number): string { 2436e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2437e41f4b71Sopenharmony_ci } 2438e41f4b71Sopenharmony_ci 2439e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2440e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2441e41f4b71Sopenharmony_ci console.info('add listener'); 2442e41f4b71Sopenharmony_ci this.listeners.push(listener); 2443e41f4b71Sopenharmony_ci } 2444e41f4b71Sopenharmony_ci } 2445e41f4b71Sopenharmony_ci 2446e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2447e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2448e41f4b71Sopenharmony_ci if (pos >= 0) { 2449e41f4b71Sopenharmony_ci console.info('remove listener'); 2450e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2451e41f4b71Sopenharmony_ci } 2452e41f4b71Sopenharmony_ci } 2453e41f4b71Sopenharmony_ci 2454e41f4b71Sopenharmony_ci notifyDataReload(): void { 2455e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2456e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2457e41f4b71Sopenharmony_ci // Method 2: listener.onDatasetChange([{type: DataOperationType.RELOAD}]); 2458e41f4b71Sopenharmony_ci }) 2459e41f4b71Sopenharmony_ci } 2460e41f4b71Sopenharmony_ci 2461e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2462e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2463e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2464e41f4b71Sopenharmony_ci }) 2465e41f4b71Sopenharmony_ci } 2466e41f4b71Sopenharmony_ci 2467e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2468e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2469e41f4b71Sopenharmony_ci listener.onDataChange(index); 2470e41f4b71Sopenharmony_ci }) 2471e41f4b71Sopenharmony_ci } 2472e41f4b71Sopenharmony_ci 2473e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2474e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2475e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2476e41f4b71Sopenharmony_ci }) 2477e41f4b71Sopenharmony_ci } 2478e41f4b71Sopenharmony_ci 2479e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2480e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2481e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2482e41f4b71Sopenharmony_ci }) 2483e41f4b71Sopenharmony_ci } 2484e41f4b71Sopenharmony_ci 2485e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]):void{ 2486e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2487e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 2488e41f4b71Sopenharmony_ci }) 2489e41f4b71Sopenharmony_ci } 2490e41f4b71Sopenharmony_ci} 2491e41f4b71Sopenharmony_ci 2492e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 2493e41f4b71Sopenharmony_ci private dataArray: string[] = []; 2494e41f4b71Sopenharmony_ci 2495e41f4b71Sopenharmony_ci public totalCount(): number { 2496e41f4b71Sopenharmony_ci return this.dataArray.length; 2497e41f4b71Sopenharmony_ci } 2498e41f4b71Sopenharmony_ci 2499e41f4b71Sopenharmony_ci public getData(index: number): string { 2500e41f4b71Sopenharmony_ci return this.dataArray[index]; 2501e41f4b71Sopenharmony_ci } 2502e41f4b71Sopenharmony_ci 2503e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 2504e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2505e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2506e41f4b71Sopenharmony_ci } 2507e41f4b71Sopenharmony_ci 2508e41f4b71Sopenharmony_ci public pushData(data: string): void { 2509e41f4b71Sopenharmony_ci this.dataArray.push(data); 2510e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2511e41f4b71Sopenharmony_ci } 2512e41f4b71Sopenharmony_ci 2513e41f4b71Sopenharmony_ci public deleteData(index: number): void { 2514e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 2515e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 2516e41f4b71Sopenharmony_ci } 2517e41f4b71Sopenharmony_ci 2518e41f4b71Sopenharmony_ci public changeData(index: number): void { 2519e41f4b71Sopenharmony_ci this.notifyDataChange(index); 2520e41f4b71Sopenharmony_ci } 2521e41f4b71Sopenharmony_ci 2522e41f4b71Sopenharmony_ci operateData():void { 2523e41f4b71Sopenharmony_ci const totalCount = this.dataArray.length; 2524e41f4b71Sopenharmony_ci const batch=5; 2525e41f4b71Sopenharmony_ci for (let i = totalCount; i < totalCount + batch; i++) { 2526e41f4b71Sopenharmony_ci this.dataArray.push(`Hello ${i}`) 2527e41f4b71Sopenharmony_ci } 2528e41f4b71Sopenharmony_ci this.notifyDatasetChange([{type:DataOperationType.ADD, index: totalCount-1, count:batch}]) 2529e41f4b71Sopenharmony_ci } 2530e41f4b71Sopenharmony_ci} 2531e41f4b71Sopenharmony_ci 2532e41f4b71Sopenharmony_ci@Entry 2533e41f4b71Sopenharmony_ci@Component 2534e41f4b71Sopenharmony_cistruct MyComponent { 2535e41f4b71Sopenharmony_ci private moved: number[] = []; 2536e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 2537e41f4b71Sopenharmony_ci 2538e41f4b71Sopenharmony_ci aboutToAppear() { 2539e41f4b71Sopenharmony_ci for (let i = 0; i <= 10; i++) { 2540e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 2541e41f4b71Sopenharmony_ci } 2542e41f4b71Sopenharmony_ci } 2543e41f4b71Sopenharmony_ci 2544e41f4b71Sopenharmony_ci build() { 2545e41f4b71Sopenharmony_ci List({ space: 3 }) { 2546e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 2547e41f4b71Sopenharmony_ci ListItem() { 2548e41f4b71Sopenharmony_ci Row() { 2549e41f4b71Sopenharmony_ci Text(item) 2550e41f4b71Sopenharmony_ci .width('100%') 2551e41f4b71Sopenharmony_ci .height(80) 2552e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 2553e41f4b71Sopenharmony_ci .onAppear(() => { 2554e41f4b71Sopenharmony_ci console.info("appear:" + item) 2555e41f4b71Sopenharmony_ci }) 2556e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2557e41f4b71Sopenharmony_ci } 2558e41f4b71Sopenharmony_ci }, (item: string) => item) 2559e41f4b71Sopenharmony_ci }.cachedCount(10) 2560e41f4b71Sopenharmony_ci .onScrollIndex((start, end, center) => { 2561e41f4b71Sopenharmony_ci if (end === this.data.totalCount() - 1) { 2562e41f4b71Sopenharmony_ci console.log('scroll to end') 2563e41f4b71Sopenharmony_ci this.data.operateData(); 2564e41f4b71Sopenharmony_ci } 2565e41f4b71Sopenharmony_ci }) 2566e41f4b71Sopenharmony_ci } 2567e41f4b71Sopenharmony_ci} 2568e41f4b71Sopenharmony_ci``` 2569e41f4b71Sopenharmony_ci 2570e41f4b71Sopenharmony_ciFixed result 2571e41f4b71Sopenharmony_ci 2572