ArkTS also provides the ability to control rendering. Conditional rendering can render the UI content in the corresponding state according to the different states of the application. Circular rendering iteratively fetches data from a data source and creates the appropriate components during each iteration.
1 -> Conditional rendering
Use if/else for conditional rendering.
illustrate
if/else conditional statements can use state variables.
Use if/else to make the rendering of a child component dependent on a conditional statement.
Must be used within the container assembly.
Some container components limit the type or number of subcomponents, and when you use if/else in those components, these restrictions will also apply to the components created in the if/else statement. For example, if only the GridItem component is supported by the child components of the Grid container component, and if if/else is used in the Grid, only the GridItem component is allowed in the if/else statement.
Column() {
if (this.count < 0) {
Text('count is negative').fontSize(14)
} else if (this.count % 2 === 0) {
Text('count is even').fontSize(14)
} else {
Text('count is odd').fontSize(14)
}
}
2 -> Render in a loop
Fetch data from an array with forEach looping and creating a component for each data item reduces code complexity.
ForEach(
arr: any[],
itemGenerator: (item: any, index?: number) => void,
keyGenerator?: (item: any, index?: number) => string
)
illustrate
ForEach must be used within the container component.
The generated child component should be one that is allowed to be included in the ForEach parent container component.
Allows if/else conditional rendering to be included in the child component generator function.
// test.ets
@Entry
@Component
struct MyComponent {
@State arr: number[] = [10, 20, 30]
build() {
Column({ space: 5 }) {
Button('Reverse Array')
.onClick(() => {
this.arr.reverse()
})
ForEach(this.arr, (item: number) => {
Text(`item value: ${item}`).fontSize(18)
Divider().strokeWidth(2)
}, (item: number) => item.toString())
}
}
}
3 -> Data lazy loading
LazyForEach allows you to iterate on data on-demand from the provided data sources and create the appropriate components during each iteration.
LazyForEach(
dataSource: IDataSource,
itemGenerator: (item: any) => void,
keyGenerator?: (item: any) => string
): void
interface IDataSource {
totalCount(): number;
getData(index: number): any;
registerDataChangeListener(listener: DataChangeListener): void;
unregisterDataChangeListener(listener: DataChangeListener): void;
}
interface DataChangeListener {
onDataReloaded(): void;
onDataAdd(index: number): void;
onDataMove(from: number, to: number): void;
onDataDelete(index: number): void;
onDataChange(index: number): void;
}
3.1 -> IDataSource type description
3.2 -> DataChangeListener类型说明
// test2.ets
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.png', '/path/image1.png', '/path/image2.png', '/path/image3.png']
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(50).height(50)
Text(item).fontSize(20).margin({ left: 10 })
}.margin({ left: 10, right: 10 })
}
.onClick(() => {
// 每点击一次列表项,数据增加一项
this.data.pushData('/path/image' + this.data.totalCount() + '.png')
})
}, item => item)
}
}
}
illustrate
LazyForEach must be used in the container component, currently only the List, Grid, and Swiper components support lazy loading of data (i.e., only the visible part and a small amount of data before and after it are loaded for buffering), and the other components still load all the data at once.
LazyForEach must be created and only one child component is allowed to be created in each iteration.
The generated child component must be a child component that is allowed to be included in the LazyForEach parent container component.
LazyForEach is allowed to be included in if/else conditional rendering statements, but not if/else conditional rendering statements are allowed to appear in LazyForEach.
For high-performance rendering, when updating the UI via the onDataChange method of the DataChangeListener object, a component refresh is triggered only if a state variable is used in the child component created in the itemGenerator.
The order in which the itemGenerator function is called is not necessarily the same as that of the data items in the data source, so do not assume whether the itemGenerator and keyGenerator functions are executed and in the order in which they are executed. For example, the following example might not work:
LazyForEach(dataSource,
item => Text('${item.i}. item.data.label')),
item => item.data.id.toString())
Top comments (0)