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![LazyForEach-Render-DifferentKey](./figures/LazyForEach-Render-DifferentKey.gif)
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![LazyForEach-Render-SameKey](./figures/LazyForEach-Render-SameKey.gif)
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![LazyForEach-Add-Data](./figures/LazyForEach-Add-Data.gif)
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![LazyForEach-Delete-Data](./figures/LazyForEach-Delete-Data.gif)
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![LazyForEach-Exchange-Data](./figures/LazyForEach-Exchange-Data.gif)
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![LazyForEach-Change-SingleData](./figures/LazyForEach-Change-SingleData.gif)
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![LazyForEach-Reload-Data](./figures/LazyForEach-Reload-Data.gif)
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![LazyForEach-Change-MultiData](./figures/LazyForEach-Change-MultiData.gif)  
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![LazyForEach-Change-MultiData2](./figures/LazyForEach-Change-MultiData2.gif)  
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![LazyForEach-Change-SubProperty](./figures/LazyForEach-Change-SubProperty.gif)
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![LazyForEach-Drag-Sort](figures/ForEach-Drag-Sort.gif)
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  ![LazyForEach-Render-Not-Expected](./figures/LazyForEach-Render-Not-Expected.gif)
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  ![LazyForEach-Render-Not-Expected-Repair](./figures/LazyForEach-Render-Not-Expected-Repair.gif)
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  ![LazyForEach-Image-Flush](./figures/LazyForEach-Image-Flush.gif)
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  ![LazyForEach-Image-Flush-Repair](./figures/LazyForEach-Image-Flush-Repair.gif)
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  ![LazyForEach-ObjectLink-NotRenderUI](./figures/LazyForEach-ObjectLink-NotRenderUI.gif)
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  ![LazyForEach-ObjectLink-NotRenderUI-Repair](./figures/LazyForEach-ObjectLink-NotRenderUI-Repair.gif)
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![LazyForEach-Screen-Flicker](figures/LazyForEach-Screen-Flicker.gif)
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![LazyForEach-Screen-Flicker-Repair](figures/LazyForEach-Screen-Flicker-Repair.gif)
2572