LazyForEach itera datos a pedido desde la fuente de datos proporcionada y crea los componentes correspondientes durante cada iteración. Cuando se usa LazyForEach en un contenedor de desplazamiento, el marco creará componentes a pedido según el área visible del contenedor de desplazamiento. Cuando el componente se dibuja fuera del área visible, el marco destruirá y reciclará el componente para reducir el uso de memoria. .
1. Descripción de la interfaz
LazyForEach(
dataSource: IDataSource, // 需要进行数据迭代的数据源
itemGenerator: (item: any) => void, // 子组件生成函数
keyGenerator?: (item: any) => string // (可选) .键值生成函数
): void
interface IDataSource {
totalCount(): number; // Get total count of data
getData(index: number): any; // Get single data by index
registerDataChangeListener(listener: DataChangeListener): void; // Register listener to listening data changes
unregisterDataChangeListener(listener: DataChangeListener): void; // Unregister listener
}
interface DataChangeListener {
onDataReloaded(): void; // Called while data reloaded
onDataAdd(index: number): void; // Called while single data added
onDataMove(from: number, to: number): void; // Called while single data moved
onDataDelete(index: number): void; // Called while single data deleted
onDataChange(index: number): void; // Called while single data changed
.}
2. Descripción del tipo IDataSource
interface IDataSource {
totalCount(): number;
getData(index: number): any;
registerDataChangeListener(listener: DataChangeListener): void;
unregisterDataChangeListener(listener: DataChangeListener): void;
}
3. Descripción del tipo DataChangeListener
4. Restricciones de uso
LazyForEach debe usarse dentro de los componentes del contenedor. Solo los componentes List, Grid y Swiper admiten la carga diferida de datos (es decir, solo la parte visible y una pequeña cantidad de datos antes y después se cargan para el almacenamiento en búfer). Otros componentes todavía se cargan todos los datos a la vez.
LazyForEach debe crear y solo puede crear un componente secundario en cada iteración.
Los componentes secundarios generados deben ser componentes secundarios que puedan incluirse en el componente contenedor principal de LazyForEach.
LazyForEach puede incluirse en declaraciones de representación condicional if/else, y las declaraciones de representación condicional if/else también pueden aparecer en LazyForEach.
El generador de valores clave debe generar un valor único para cada dato. Si los valores clave son los mismos, el marco ignorará los componentes de la interfaz de usuario con los mismos valores clave y no se podrán mostrar en el contenedor principal.
LazyForEach debe usar el objeto DataChangeListener para actualizar. Cuando el primer parámetro dataSource usa una variable de estado, el cambio de la variable de estado no activará la actualización de la interfaz de usuario de LazyForEach.
Para una representación de alto rendimiento, al actualizar la interfaz de usuario mediante el método onDataChange del objeto DataChangeListener, se debe generar un valor clave diferente para activar la actualización del componente.
El orden de llamada de la función itemGenerator no es necesariamente el mismo que el de los elementos de datos en la fuente de datos. Durante el proceso de desarrollo, no asuma si las funciones itemGenerator y keyGenerator se ejecutan ni su orden de ejecución. Por ejemplo, es posible que el siguiente ejemplo no funcione correctamente:
LazyForEach(dataSource,
item => Text(`${item.i}. item.data.label`),
item => item.data.id.toString())
5. Ejemplo
// Basic implementation of IDataSource to handle data listener
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): any {
return undefined;
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
})
}
}
class MyDataSource extends BasicDataSource {
private dataArray: string[] = ['/path/image0', '/path/image1', '/path/image2', '/path/image3'];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): any {
return this.dataArray[index];
}
public addData(index: number, data: string): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: string): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
}
@Entry
@Component
struct MyComponent {
private data: MyDataSource = new MyDataSource();
build() {
List({ space: 3 }) {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
Image(item).width('30%').height(50)
Text(item).fontSize(20).margin({ left: 10 })
}.margin({ left: 10, right: 10 })
}
.onClick(() => {
this.data.pushData('/path/image' + this.data.totalCount());
})
}, item => item)
}
}
}