Foreword
this article code case based on api13.
In actual development, we often encounter the situation of custom components, such as common list components, tab components, etc. Due to the different styles of users, subcomponents change dynamically. In view of this situation, we have to let users pass the subcomponent view and how to receive this UI view. This is the function of @ BuilderParam decorator.
Simple Case
simply encapsulate a common List component. Since the data and UI layout of each List are different, these two blocks need to be exposed to the user. The code is as follows:
/**
* AUTHOR:AbnerMing
* DATE:2025/2/13
* INTRODUCE:list
* */
@Component
export struct ListView {
dataList?: Object[]
@BuilderParam itemLayout: (item: Object, index: number) => void //子视图
build() {
List() {
ForEach(this.dataList, (item: Object, index: number) => {
ListItem() {
this.itemLayout(item, index)
}
})
}
}
}
the above custom List component can be used on any page, just passing data and subviews.
@Entry
@Component
struct Index {
@Builder
itemLayout(item: Object, index: number) {
Text(item.toString())
}
build() {
Column() {
ListView({
dataList: [0, 1, 2, 3, 4, 5, 6],
itemLayout: this.itemLayout
})
}
.height('100%')
.width('100%')
}
}
@ BuilderParam decorator allows UI components to give dynamic changes, which can achieve different effects according to their own needs and avoid instance adds the same functionality, this results in a higher degree of component reuse and code decoupling.
Mode of use
the @ BuilderParam decorator, commonly used in custom components, is exposed to the user for calling, and is used to accept the functions decorated by the @ Builder decorator. The usage is very simple, and the format is as follows:
@BuilderParam test: () => void
if you receive parameters, you can add them directly in parentheses.
In addition to the normal UI component passed by the caller, we can also initialize a default view, which is directly equal to the following, so that the default view will be loaded if it is not passed.
@Builder
testView() {
}
@BuilderParam test: () => void = this.testView()
this points to the problem
As shown below, we have customized a component and defined two @ BuilderParam to receive the passed UI view:
@Component
export struct TestView {
testContent: string = "TestView"
@BuilderParam layout: () => void
@BuilderParam layout2: () => void
build() {
Column() {
if (this.layout != undefined) {
this.layout()
}
if (this.layout2 != undefined) {
this.layout2()
}
}
}
}
we call the functions decorated by @ Builder in three ways.
@Entry
@Component
struct Index {
testContent: string = "Index"
@Builder
testView() {
Text(`${this.testContent}`)
.fontSize(20)
.margin({ top: 20 })
.fontWeight(FontWeight.Bold)
}
build() {
Column() {
this.testView()
TestView({ layout: this.testView })
TestView({
layout2: () => {
this.testView()
}
})
}
.height('100%')
.width('100%')
}
}
After running, the effect is as follows:
as we can see, calling directly @ Builder decorated function, that is this.testView() this line of code, this points to the current Index class, and its value is also the Index value.
When we pass the TestView({ layout: this.testView }) code as a parameter to @ BuilderParam, we can find that this does not refer to the Index class, but to the custom component TestView, which takes the value defined in TestView.
When we use custom components in a different way, we use them in the following way:
TestView({
layout2: () => {
this.testView()
}
})
it can be found that this is switched to the current class Index, because the arrow function's this points to the host object, so its value is in the Index class.
Therefore, when passing the UI view with @ BuilderParam, we must pay attention to the pointing problem of this, which is why many students encounter the reason why the data is not refreshed in the function decorated by @ Builder is that this points incorrectly.
Data Update
update @ BuilderParam decorator, the original intention is to update the correspondingThe function modified by @ Builder has been mainly explained in the article "Hongmeng Development: Understanding @ Builder Decorator", which will be summarized again here.
Simply customize a component, use the @ BuilderParam decorator, and expose a UI view to the outside.
@Component
export struct TestView {
@BuilderParam layout: () => void
build() {
Column() {
if (this.layout != undefined) {
this.layout()
}
}
}
}
this points to the problem described above. If the data is in this page, you must use the arrow function to call the function decorated by @ Builder to update the data.
@Entry
@Component
struct Index {
@State testContent: string = "test data 1"
@Builder
textView() {
Text(this.testContent)
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
build() {
Column() {
TestView({
layout: () => {
this.textView()
}
})
Button("click")
.onClick(() => {
this.testContent = "test data 2"
})
}
.height('100%')
.width('100%')
}
}
Related Summary
when declaring @ BuilderParam, if there is no default value, an abnormal crash will occur without passing it. In order to solve this problem, there are two schemes. Scheme 1 is to actively set the default value:
@Builder
testView() {
}
@BuilderParam test: () => void = this.testView()
scheme 2, non-empty verification is performed at the place where the call is made:
@BuilderParam test: () => void
build() {
if (this.test != undefined) {
this.test()
}
}
@ BuilderParam is used to receive functions defined by @ Builder, both private and global.
Defines the global @ Builder.
@Builder
export function TextView() {
Text("test data 1")
.fontSize(20)
.fontWeight(FontWeight.Bold)
}
Call
@Entry
@Component
struct Index {
build() {
Column() {
TestView({ layout: TextView })
}
.height('100%')
.width('100%')
}
}
Top comments (0)