DEV Community

HarmonyOS
HarmonyOS

Posted on

How to deal with the problem that the internal state of wrapBuilder function cannot be refreshed

Read the original article:How to deal with the problem that the internal state of wrapBuilder function cannot be refreshed

How to deal with the problem that the internal state of wrapBuilder function cannot be refreshed

Problem description

Changes in the parameters passed into the WrapBuilder function did not cause the internal UI to refresh.

Background knowledge

Builder function: ArkUI provides a lightweight UI element reuse mechanism @Builder. The internal UI structure of this custom component is fixed and only transmits data with the user. Developers can abstract the reused UI elements into a method and call it in the build method. For details, see @Builder decorator: custom build function.

wrapBuilder function: When the @Builder method is assigned to a variable or array, the assigned variable or array cannot be used in the UI method. To solve this problem, wrapBuilder is introduced as a global @Builderwrapper function. The parameter of wrapBuilder returns the WrappedBuilder object, so that the global @Builder can be assigned and passed. For details, see wrapBuilder: Wrapping the global @Builder.

Positioning ideas

The global @Builder returns the WrappedBuilder object as a parameter of wrapBuilder, so that the global @Builder can be assigned and passed. However, there are restrictions on its parameter passing, and failure to meet the restrictions will cause the UI to not refresh.

Parameter passing restrictions:

@Builder triggers dynamic UI rendering by passing parameters by reference, and there can only be one parameter;
@Builder will not trigger dynamic rendering of UI if two or more parameters are passed in;
The parameters passed by @Builder include both passing by value and passing by reference, which will not trigger dynamic rendering of the UI;
The parameters of @Builder must be passed in the form of object literals, with the required properties passed in one by one, to trigger dynamic rendering of the UI.

Solution

1.When the Builder has only one parameter, the UI will refresh if it is passed by reference, but not if it is passed by value

The Builder code example is as follows:

class Tmp { paramA1: string = '' } /** * Pass by reference, UI will refresh * @param $$ * */ @Builder function test($$: Tmp) { Column() { HelloComponent({ message: $$.paramA1 }) } } /** * Pass by value, UI will not be updated * @param message * */ @Builder function test2(message: string) { Column() { HelloComponent({ message: message }) } } @Component struct HelloComponent { @Prop message: string build() { Column() { Text(this.message) } } } let globalBuilder2: WrappedBuilder<[string]> = wrapBuilder(test2); let globalBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(test); 
Enter fullscreen mode Exit fullscreen mode

The component code example is as follows:

@Entry @Component export struct WrappedBuilderDemoPage { @State message: string = 'message' build() { Row() { Column({ space: 10 }) { Button(`Click to change the builder value`).onClick(() => { this.message = util.generateRandomUUID() }) Column() { Text('Parameters passed to Builder') Text(this.message) }.width('100%') .alignItems(HorizontalAlign.Start) Text('Pass by reference').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 }) Column() { Column() { Text('Builder呈现的').margin({ bottom: 10 }) globalBuilder.builder({ paramA1: this.message }) }.alignItems(HorizontalAlign.Start) } .width('100%') .justifyContent(FlexAlign.Start) .alignItems(HorizontalAlign.Start) Text('Pass by value').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 }) Column() { Column() { Text('Builder呈现的').margin({ bottom: 10 }) globalBuilder2.builder(this.message) }.alignItems(HorizontalAlign.Start) } .width('100%') .justifyContent(FlexAlign.Start) .alignItems(HorizontalAlign.Start) } .width('100%') .padding(20) } .height('100%') } } 
Enter fullscreen mode Exit fullscreen mode

The effect is as follows:

2.When there are two or more parameters, the UI will be refreshed if they are passed in as object literals, but will not be refreshed if they are passed in separately

Builder code examples are as follows:

interface HelloComponentParam { message: string message2: string } /** * Multiple parameters are passed separately, and the UI will not refresh * @param message * @param message2 * */ @Builder function test(message: string, message2: string) { HelloComponent({ param: { message: message, message2: message2 } }) } /** * Multiple parameters are written into an object literal, and the UI will refresh * @param param * */ @Builder function test2(param: HelloComponentParam) { HelloComponent({ param: { message: param.message, message2: param.message2 } }) } @Component struct HelloComponent { @Prop param: HelloComponentParam = { message: "", message2: "" } build() { Column() { Text(this.param.message) Text(this.param.message2) } } } let globalBuilder: WrappedBuilder<[string, string]> = wrapBuilder(test); let globalBuilder2: WrappedBuilder<[HelloComponentParam]> = wrapBuilder(test2); 
Enter fullscreen mode Exit fullscreen mode

The component code example is as follows:

@Entry @Component export struct WrappedBuilderDemoPage { @State param: HelloComponentParam = { message: "message", message2: "message", } build() { Row() { Column({ space: 10 }) { Button(`Click to change the builder value`).onClick(() => { this.param = { message: util.generateRandomUUID(), message2: util.generateRandomUUID() } }) Column() { Text('Parameters passed to Builder') Text(JSON.stringify(this.param)) }.width('100%') .alignItems(HorizontalAlign.Start) Text('Multiple parameters are passed in separately').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 }) Column() { Column() { Text('Builder rendered').margin({ bottom: 10 }) globalBuilder.builder(this.param.message, this.param.message2) }.alignItems(HorizontalAlign.Start) } .width('100%') .justifyContent(FlexAlign.Start) .alignItems(HorizontalAlign.Start) Text('Multiple parameters are placed in an object literal').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 }) Column() { Column() { Text('Builder rendered').margin({ bottom: 10 }) globalBuilder2.builder({ message: this.param.message, message2: this.param.message2 }) }.alignItems(HorizontalAlign.Start) } .width('100%') .justifyContent(FlexAlign.Start) .alignItems(HorizontalAlign.Start) } .width('100%') .padding(20) } .height('100%') } } 
Enter fullscreen mode Exit fullscreen mode

The effect is as follows:

Written by Emine Inan

Top comments (0)