• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# BuilderNode
2
3The **BuilderNode** module provides APIs for a BuilderNode, a custom node that can be used to mount native components. A BuilderNode can be used only as a leaf node. For details, see [BuilderNode Development](../../ui/arkts-user-defined-arktsNode-builderNode.md).
4
5> **NOTE**
6>
7> The initial APIs of this module are supported since API version 11. Newly added APIs will be marked with a superscript to indicate their earliest API version.
8>
9> **BuilderNode** is not available in DevEco Studio Previewer.
10
11## Modules to Import
12
13```ts
14import { BuilderNode, RenderOptions, NodeRenderType } from "@kit.ArkUI";
15```
16
17## NodeRenderType
18
19Enumerates the node rendering types.
20
21**Atomic service API**: This API can be used in atomic services since API version 12.
22
23**System capability**: SystemCapability.ArkUI.ArkUI.Full
24
25| Name               | Value | Description                        |
26| ------------------- | --- | ---------------------------- |
27| RENDER_TYPE_DISPLAY | 0   | The node is displayed on the screen.|
28| RENDER_TYPE_TEXTURE | 1   | The node is exported as a texture.  |
29
30> **NOTE**
31>
32> Currently, the **RENDER_TYPE_TEXTURE** type takes effect only for the [XComponentNode](./js-apis-arkui-xcomponentNode.md) and the [BuilderNode](#buildernode-1) holding a component tree whose root node is a custom component.
33>
34> In the case of [BuilderNode](#buildernode-1), the following custom components that function as the root node support texture export: Badge, Blank, Button, CanvasGradient, CanvasPattern, CanvasRenderingContext2D, Canvas, CheckboxGroup, Checkbox, Circle, ColumnSplit, Column, ContainerSpan, Counter, DataPanel, Divider, Ellipse, Flex, Gauge, Hyperlink, ImageBitmap, ImageData, Image, Line, LoadingProgress, Marquee, Matrix2D, OffscreenCanvasRenderingContext2D, OffscreenCanvas, Path2D, Path, PatternLock, Polygon, Polyline, Progress, QRCode, Radio, Rating, Rect, RelativeContainer, RowSplit, Row, Shape, Slider, Span, Stack, TextArea, TextClock, TextInput, TextTimer, Text, Toggle, Video (not supporting the native full-screen mode), Web, XComponent
35>
36> The following components support texture export since API version 12: DatePicker, ForEach, Grid, IfElse, LazyForEach, List, Scroll, Swiper, TimePicker, @Component decorated custom components, NodeContainer, and FrameNode and RenderNode mounted to a NodeContainer.
37>
38> For details, see [Rendering and Drawing Video and Button Components at the Same Layer](../../web/web-same-layer.md).
39
40## RenderOptions
41
42Provides optional parameters for creating a BuilderNode.
43
44**Atomic service API**: This API can be used in atomic services since API version 12.
45
46**System capability**: SystemCapability.ArkUI.ArkUI.Full
47
48| Name         | Type                                  | Mandatory| Description                                                        |
49| ------------- | -------------------------------------- | ---- | ------------------------------------------------------------ |
50| selfIdealSize | [Size](js-apis-arkui-graphics.md#size) | No  | Ideal size of the node.                                            |
51| type          | [NodeRenderType](#noderendertype)      | No  | Rendering type of the node.                                            |
52| surfaceId     | string                                 | No  | Surface ID of the texture receiver. Generally, the texture receiver is an [OH_NativeImage](../apis-arkgraphics2d/_o_h___native_image.md#oh_nativeimage) instance.|
53
54## BuilderNode
55
56class BuilderNode\<Args extends Object[]>
57
58Implements a BuilderNode, which can create a component tree through the stateless UI method [@Builder](../../quick-start/arkts-builder.md) and hold the root node of the component tree. A BuilderNode cannot be defined as a state variable. The FrameNode held in the BuilderNode is only used to mount the BuilderNode to other FrameNodes as a child node. Undefined behavior may occur if you set attributes or perform operations on subnodes of the FrameNode held by the BuilderNode. Therefore, after you have obtained a [RenderNode](js-apis-arkui-renderNode.md#rendernode) through the [getFrameNode](#getframenode) method of the BuilderNode and the [getRenderNode](js-apis-arkui-frameNode.md#getrendernode) method of the [FrameNode](js-apis-arkui-frameNode.md#framenode), avoid setting the attributes or operating the subnodes through APIs of the [RenderNode](js-apis-arkui-renderNode.md#rendernode).
59
60**Atomic service API**: This API can be used in atomic services since API version 12.
61
62**System capability**: SystemCapability.ArkUI.ArkUI.Full
63
64### constructor
65
66constructor(uiContext: UIContext, options?: RenderOptions)
67
68Constructor for creating a BuilderNode. When the content generated by the BuilderNode is embedded in another RenderNode for display, that is, the RenderNode corresponding to the BuilderNode is mounted to another RenderNode for display, **selfIdealSize** in **RenderOptions** must be explicitly specified. If **selfIdealSize** is not set, the node in the builder follows the default parent component layout constraint [0, 0], which means that the size of the root node of the subtree in BuilderNode is [0, 0].
69
70**Atomic service API**: This API can be used in atomic services since API version 12.
71
72**System capability**: SystemCapability.ArkUI.ArkUI.Full
73
74| Name   | Type                                   | Mandatory| Description                                                             |
75| --------- | --------------------------------------- | ---- | ----------------------------------------------------------------- |
76| uiContext | [UIContext](js-apis-arkui-UIContext.md) | Yes  | UI context. For details about how to obtain it, see [[Obtaining UI Context](./js-apis-arkui-node.md#obtaining-ui-context).|
77| options   | [RenderOptions](#renderoptions)         | No  | Parameters for creating a BuilderNode.                                      |
78
79> **NOTE**
80> The input parameter for **uiContext** must be a valid value, that is, the UI context must be correct. If an invalid value is passed in or if no value is specified, creation will fail.
81
82### build
83
84build(builder: WrappedBuilder\<Args>, arg?: Object): void
85
86Creates a component tree based on the passed object and holds the root node of the component tree. The stateless UI method [@Builder](../../quick-start/arkts-builder.md) has at most one root node.
87Custom components are allowed. Yet, the custom components cannot use decorators, such as [@Reusable](../../quick-start/arkts-create-custom-components.md#basic-structure-of-a-custom-component), @Link, @Provide, and @Consume, for state synchronization with the owning page.
88
89> **NOTE**
90>
91> When nesting @Builder, ensure that the input objects for the inner and outer @Builder methods are consistent.
92>
93> The outermost @Builder supports only one input argument.
94
95**Atomic service API**: This API can be used in atomic services since API version 12.
96
97**System capability**: SystemCapability.ArkUI.ArkUI.Full
98
99**Parameters**
100
101| Name | Type                                                           | Mandatory| Description                                                                                  |
102| ------- | --------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------- |
103| builder | [WrappedBuilder\<Args>](../../quick-start/arkts-wrapBuilder.md) | Yes  | Stateless UI method [@Builder](../../quick-start/arkts-builder.md) required for creating a component tree.|
104| arg     | Object                                                          | No  | Argument of the builder. Only one input argument is supported, and the type of the input argument must be consistent with the type defined by @Builder.                                         |
105
106
107### BuildOptions<sup>12+</sup>
108
109Defines the optional build options.
110
111**Atomic service API**: This API can be used in atomic services since API version 12.
112
113**System capability**: SystemCapability.ArkUI.ArkUI.Full
114
115| Name         | Type                                  | Mandatory| Description                                                        |
116| ------------- | -------------------------------------- | ---- | ------------------------------------------------------------ |
117| nestingBuilderSupported |boolean | No  | Whether to support nesting **@Builder** within **@Builder**. The value **false** means that the input arguments for **@Builder** are consistent, and **true** means the opposite.<br> Default value: **false**                                         |
118
119### build<sup>12+</sup>
120
121build(builder: WrappedBuilder\<Args>, arg: Object, options: [BuildOptions](#buildoptions12)): void
122
123Creates a component tree based on the passed object and holds the root node of the component tree. The stateless UI method [@Builder](../../quick-start/arkts-builder.md) has at most one root node.
124Custom components are allowed. Yet, the custom components cannot use decorators, such as [@Reusable](../../quick-start/arkts-create-custom-components.md#basic-structure-of-a-custom-component), @Link, @Provide, and @Consume, for state synchronization with the owning page.
125
126> **NOTE**
127>
128> For details about the creation and update using @Builder, see [@Builder](../../quick-start/arkts-builder.md).
129>
130> The outermost @Builder supports only one input argument.
131
132**Atomic service API**: This API can be used in atomic services since API version 12.
133
134**System capability**: SystemCapability.ArkUI.ArkUI.Full
135
136**Parameters**
137
138| Name | Type                                                           | Mandatory| Description                                                                                   |
139| ------- | --------------------------------------------------------------- | ---- | -------------------------------------------------------------------------------------- |
140| builder | [WrappedBuilder\<Args>](../../quick-start/arkts-wrapBuilder.md) | Yes  | Stateless UI method [@Builder](../../quick-start/arkts-builder.md) required for creating a component tree.  |
141| arg     | Object                                                          | Yes  | Argument of the builder. Only one input argument is supported, and the type of the input argument must be consistent with the type defined by @Builder.                                                           |
142| options | BuildOptions                                                    | Yes  | Build options, which determine whether to support nesting **@Builder** within **@Builder**.                                        |
143
144**Example**
145```ts
146import { BuilderNode, NodeContent } from "@kit.ArkUI"
147
148interface ParamsInterface {
149  text: string;
150  func: Function;
151}
152
153@Builder
154function buildTextWithFunc(fun: Function) {
155  Text(fun())
156    .fontSize(50)
157    .fontWeight(FontWeight.Bold)
158    .margin({ bottom: 36 })
159}
160
161@Builder
162function buildText(params: ParamsInterface) {
163  Column() {
164    Text(params.text)
165      .fontSize(50)
166      .fontWeight(FontWeight.Bold)
167      .margin({ bottom: 36 })
168    buildTextWithFunc(params.func)
169  }
170}
171
172
173@Entry
174@Component
175struct Index {
176  @State message: string = "HELLO"
177  private content: NodeContent = new NodeContent();
178
179  build() {
180    Row() {
181      Column() {
182        Button('addBuilderNode')
183          .onClick(() => {
184            let buildNode = new BuilderNode<[ParamsInterface]>(this.getUIContext());
185            buildNode.build(wrapBuilder<[ParamsInterface]>(buildText), {
186              text: this.message, func: () => {
187                return "FUNCTION"
188              }
189            }, { nestingBuilderSupported: true });
190            this.content.addFrameNode(buildNode.getFrameNode());
191            buildNode.dispose();
192          })
193        ContentSlot(this.content)
194      }
195      .id("column")
196      .width('100%')
197      .height('100%')
198    }
199    .height('100%')
200  }
201}
202```
203
204
205### getFrameNode
206
207getFrameNode(): FrameNode | null
208
209Obtains the FrameNode in the BuilderNode. The FrameNode is generated only after the BuilderNode executes the build operation.
210
211**Atomic service API**: This API can be used in atomic services since API version 12.
212
213**System capability**: SystemCapability.ArkUI.ArkUI.Full
214
215**Return value**
216
217| Type                                                     | Description                                                                 |
218| --------------------------------------------------------- | --------------------------------------------------------------------- |
219| [FrameNode](js-apis-arkui-frameNode.md#framenode) \| null | **FrameNode** object. If no such object is held by the **BuilderNode** instance, null is returned.|
220
221**Example 1**
222
223In this example, the BuilderNode is returned as the root node of the **\<NodeContainer>**.
224
225```ts
226import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI"
227
228class Params {
229  text: string = ""
230  constructor(text: string) {
231    this.text = text;
232  }
233}
234
235@Builder
236function buildText(params: Params) {
237  Column() {
238    Text(params.text)
239      .fontSize(50)
240      .fontWeight(FontWeight.Bold)
241      .margin({bottom: 36})
242  }
243}
244
245class TextNodeController extends NodeController {
246  private textNode: BuilderNode<[Params]> | null = null;
247  private message: string = "DEFAULT";
248
249  constructor(message: string) {
250    super();
251    this.message = message;
252  }
253
254  makeNode(context: UIContext): FrameNode | null {
255    this.textNode = new BuilderNode(context);
256    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message))
257
258    return this.textNode.getFrameNode();
259  }
260}
261
262@Entry
263@Component
264struct Index {
265  @State message: string = "hello"
266
267  build() {
268    Row() {
269      Column() {
270        NodeContainer(new TextNodeController(this.message))
271          .width('100%')
272          .height(100)
273          .backgroundColor('#FFF0F0F0')
274      }
275      .width('100%')
276      .height('100%')
277    }
278    .height('100%')
279  }
280}
281```
282
283**Example 2**
284
285This example shows how to mount a FrameNode within a BuilderNode to another FrameNode.
286
287```ts
288import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI"
289
290class Params {
291  text: string = ""
292
293  constructor(text: string) {
294    this.text = text;
295  }
296}
297
298@Builder
299function buildText(params: Params) {
300  Column() {
301    Text(params.text)
302      .fontSize(50)
303      .fontWeight(FontWeight.Bold)
304      .margin({ bottom: 36 })
305  }
306}
307
308class TextNodeController extends NodeController {
309  private rootNode: FrameNode | null = null;
310  private textNode: BuilderNode<[Params]> | null = null;
311  private message: string = "DEFAULT";
312
313  constructor(message: string) {
314    super();
315    this.message = message;
316  }
317
318  makeNode(context: UIContext): FrameNode | null {
319    this.rootNode = new FrameNode(context);
320    this.textNode = new BuilderNode(context, { selfIdealSize: { width: 150, height: 150 } });
321    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
322    if (this.rootNode !== null) {
323      this.rootNode.appendChild(this.textNode?.getFrameNode());
324    }
325
326    return this.rootNode;
327  }
328}
329
330@Entry
331@Component
332struct Index {
333  @State message: string = "hello"
334
335  build() {
336    Row() {
337      Column() {
338        NodeContainer(new TextNodeController(this.message))
339          .width('100%')
340          .height(100)
341          .backgroundColor('#FFF0F0F0')
342      }
343      .width('100%')
344      .height('100%')
345    }
346    .height('100%')
347  }
348}
349```
350
351**Example 3**
352
353This example shows how to mount a BuilderNode's RenderNode under another RenderNode. Since the RenderNode does not pass layout constraints, this mode of mounting nodes is not recommended.
354
355```ts
356import { NodeController, BuilderNode, FrameNode, UIContext, RenderNode } from "@kit.ArkUI"
357
358class Params {
359  text: string = ""
360
361  constructor(text: string) {
362    this.text = text;
363  }
364}
365
366@Builder
367function buildText(params: Params) {
368  Column() {
369    Text(params.text)
370      .fontSize(50)
371      .fontWeight(FontWeight.Bold)
372      .margin({ bottom: 36 })
373  }
374}
375
376class TextNodeController extends NodeController {
377  private rootNode: FrameNode | null = null;
378  private textNode: BuilderNode<[Params]> | null = null;
379  private message: string = "DEFAULT";
380
381  constructor(message: string) {
382    super();
383    this.message = message;
384  }
385
386  makeNode(context: UIContext): FrameNode | null {
387    this.rootNode = new FrameNode(context);
388    let renderNode = new RenderNode();
389    renderNode.clipToFrame = false;
390    this.textNode = new BuilderNode(context, { selfIdealSize: { width: 150, height: 150 } });
391    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
392    const textRenderNode = this.textNode?.getFrameNode()?.getRenderNode();
393
394    const rootRenderNode = this.rootNode.getRenderNode();
395    if (rootRenderNode !== null) {
396      rootRenderNode.appendChild(renderNode);
397      renderNode.appendChild(textRenderNode);
398    }
399
400    return this.rootNode;
401  }
402}
403
404@Entry
405@Component
406struct Index {
407  @State message: string = "hello"
408
409  build() {
410    Row() {
411      Column() {
412        NodeContainer(new TextNodeController(this.message))
413          .width('100%')
414          .height(100)
415          .backgroundColor('#FFF0F0F0')
416      }
417      .width('100%')
418      .height('100%')
419    }
420    .height('100%')
421  }
422}
423```
424
425### update
426
427update(arg: Object): void
428
429Updates this BuilderNode based on the provided parameter, which is of the same type as the input parameter passed to the [build](#build) API. To call this API on a custom component, the variable used in the component must be defined as the @Prop type.
430
431**Atomic service API**: This API can be used in atomic services since API version 12.
432
433**System capability**: SystemCapability.ArkUI.ArkUI.Full
434
435**Parameters**
436
437| Name| Type  | Mandatory| Description                                                                    |
438| ------ | ------ | ---- | ------------------------------------------------------------------------ |
439| arg    | Object | Yes  | Parameter used to update the BuilderNode. It is of the same type as the parameter passed to the [build](#build) API.|
440
441**Example**
442```ts
443import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI"
444
445class Params {
446  text: string = ""
447  constructor(text: string) {
448    this.text = text;
449  }
450}
451
452// Custom component
453@Component
454struct TextBuilder {
455  @Prop message: string = "TextBuilder";
456
457  build() {
458    Row() {
459      Column() {
460        Text(this.message)
461          .fontSize(50)
462          .fontWeight(FontWeight.Bold)
463          .margin({bottom: 36})
464          .backgroundColor(Color.Gray)
465      }
466    }
467  }
468}
469
470@Builder
471function buildText(params: Params) {
472  Column() {
473    Text(params.text)
474      .fontSize(50)
475      .fontWeight(FontWeight.Bold)
476      .margin({ bottom: 36 })
477    TextBuilder({message: params.text}) // Custom component
478  }
479}
480
481class TextNodeController extends NodeController {
482  private rootNode: FrameNode | null = null;
483  private textNode: BuilderNode<[Params]> | null = null;
484  private message: string = "";
485
486  constructor(message: string) {
487    super()
488    this.message = message
489  }
490
491  makeNode(context: UIContext): FrameNode | null {
492    this.textNode = new BuilderNode(context);
493    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message))
494    return this.textNode.getFrameNode();
495  }
496
497  update(message: string) {
498    if (this.textNode !== null) {
499      this.textNode.update(new Params(message));
500    }
501  }
502}
503
504@Entry
505@Component
506struct Index {
507  @State message: string = "hello"
508  private textNodeController: TextNodeController = new TextNodeController(this.message);
509  private count = 0;
510
511  build() {
512    Row() {
513      Column() {
514        NodeContainer(this.textNodeController)
515          .width('100%')
516          .height(200)
517          .backgroundColor('#FFF0F0F0')
518        Button('Update')
519          .onClick(() => {
520            this.count += 1;
521            const message = "Update " + this.count.toString();
522            this.textNodeController.update(message);
523          })
524      }
525      .width('100%')
526      .height('100%')
527    }
528    .height('100%')
529  }
530}
531```
532
533### postTouchEvent
534
535postTouchEvent(event: TouchEvent): boolean
536
537Dispatches an event to the FrameNode created by this BuilderNode.
538
539**Atomic service API**: This API can be used in atomic services since API version 12.
540
541**System capability**: SystemCapability.ArkUI.ArkUI.Full
542
543**Parameters**
544
545| Name| Type                                                                     | Mandatory| Description      |
546| ------ | ------------------------------------------------------------------------- | ---- | ---------- |
547| event  | [TouchEvent](arkui-ts/ts-universal-events-touch.md#touchevent) | Yes  | Touch event.|
548
549**Return value**
550
551| Type   | Description              |
552| ------- | ------------------ |
553| boolean | Whether the event is successfully dispatched.|
554
555**Example**
556
557```ts
558import { NodeController, BuilderNode, FrameNode, UIContext } from '@kit.ArkUI';
559
560class Params {
561  text: string = "this is a text"
562}
563
564@Builder
565function ButtonBuilder(params: Params) {
566  Column() {
567    Button(`button ` + params.text)
568      .borderWidth(2)
569      .backgroundColor(Color.Orange)
570      .width("100%")
571      .height("100%")
572      .gesture(
573        TapGesture()
574          .onAction((event: GestureEvent) => {
575            console.log("TapGesture");
576          })
577      )
578  }
579  .width(500)
580  .height(300)
581  .backgroundColor(Color.Gray)
582}
583
584class MyNodeController extends NodeController {
585  private rootNode: BuilderNode<[Params]> | null = null;
586  private wrapBuilder: WrappedBuilder<[Params]> = wrapBuilder(ButtonBuilder);
587
588  makeNode(uiContext: UIContext): FrameNode | null {
589    this.rootNode = new BuilderNode(uiContext);
590    this.rootNode.build(this.wrapBuilder, { text: "this is a string" })
591    return this.rootNode.getFrameNode();
592  }
593
594  postTouchEvent(touchEvent: TouchEvent): void {
595    if(this.rootNode == null){
596      return;
597    }
598    let result = this.rootNode.postTouchEvent(touchEvent);
599    console.log("result " + result);
600  }
601}
602
603@Entry
604@Component
605struct MyComponent {
606  private nodeController: MyNodeController = new MyNodeController();
607
608  build() {
609    Column() {
610      NodeContainer(this.nodeController)
611        .height(300)
612        .width(500)
613
614      Column()
615        .width(500)
616        .height(300)
617        .backgroundColor(Color.Pink)
618        .onTouch((event) => {
619          if(event != undefined){
620            this.nodeController.postTouchEvent(event);
621          }
622        })
623    }
624  }
625}
626```
627
628### dispose<sup>12+</sup>
629
630dispose(): void
631
632Releases this BuilderNode immediately. Calling **dispose** on a **BuilderNode** object breaks its reference to the backend entity node, and also simultaneously severs the references of its contained FrameNode and RenderNode to their respective entity nodes.
633
634**Atomic service API**: This API can be used in atomic services since API version 12.
635
636**System capability**: SystemCapability.ArkUI.ArkUI.Full
637
638```ts
639import { RenderNode, FrameNode, NodeController, BuilderNode } from "@kit.ArkUI"
640
641@Component
642struct TestComponent {
643  build() {
644    Column() {
645      Text('This is a BuilderNode.')
646        .fontSize(16)
647        .fontWeight(FontWeight.Bold)
648    }
649    .width('100%')
650    .backgroundColor(Color.Gray)
651  }
652
653  aboutToAppear() {
654    console.error('aboutToAppear');
655  }
656
657  aboutToDisappear() {
658    console.error('aboutToDisappear');
659  }
660}
661
662@Builder
663function buildComponent() {
664  TestComponent()
665}
666
667class MyNodeController extends NodeController {
668  private rootNode: FrameNode | null = null;
669  private builderNode: BuilderNode<[]> | null = null;
670
671  makeNode(uiContext: UIContext): FrameNode | null {
672    this.rootNode = new FrameNode(uiContext);
673    this.builderNode = new BuilderNode(uiContext, { selfIdealSize: { width: 200, height: 100 } });
674    this.builderNode.build(new WrappedBuilder(buildComponent));
675
676    const rootRenderNode = this.rootNode!.getRenderNode();
677    if (rootRenderNode !== null) {
678      rootRenderNode.size = { width: 200, height: 200 };
679      rootRenderNode.backgroundColor = 0xff00ff00;
680      rootRenderNode.appendChild(this.builderNode!.getFrameNode()!.getRenderNode());
681    }
682
683    return this.rootNode;
684  }
685
686  dispose() {
687    if (this.builderNode !== null) {
688      this.builderNode.dispose();
689    }
690  }
691
692  removeBuilderNode() {
693    const rootRenderNode = this.rootNode!.getRenderNode();
694    if (rootRenderNode !== null && this.builderNode !== null && this.builderNode.getFrameNode() !== null) {
695      rootRenderNode.removeChild(this.builderNode!.getFrameNode()!.getRenderNode());
696    }
697  }
698}
699
700@Entry
701@Component
702struct Index {
703  private myNodeController: MyNodeController = new MyNodeController();
704
705  build() {
706    Column({ space: 4 }) {
707      NodeContainer(this.myNodeController)
708      Button('BuilderNode dispose')
709        .onClick(() => {
710          this.myNodeController.removeBuilderNode();
711          this.myNodeController.dispose();
712        })
713        .width('100%')
714    }
715  }
716}
717```
718
719### reuse<sup>12+</sup>
720
721reuse(param?: Object): void
722
723Passes the reuse event to the custom component in this BuilderNode.
724
725**Atomic service API**: This API can be used in atomic services since API version 12.
726
727**System capability**: SystemCapability.ArkUI.ArkUI.Full
728
729**Parameters**
730
731| Name| Type  | Mandatory| Description                                                                    |
732| ------ | ------ | ---- | ------------------------------------------------------------------------ |
733| param  | Object | No  | Parameter used to reuse the BuilderNode. It is of the same type as the parameter passed to the [build](#build) API.|
734
735### recycle<sup>12+</sup>
736
737recycle(): void
738
739Passes the recycle event to the custom component in this BuiderNode.
740
741**Atomic service API**: This API can be used in atomic services since API version 12.
742
743**System capability**: SystemCapability.ArkUI.ArkUI.Full
744
745```ts
746import { FrameNode,NodeController,BuilderNode,UIContext } from "@kit.ArkUI"
747
748class MyDataSource {
749  private dataArray: string[] = [];
750  private listener: DataChangeListener | null = null
751
752  public totalCount(): number {
753    return this.dataArray.length;
754  }
755
756  public getData(index: number) {
757    return this.dataArray[index];
758  }
759
760  public pushData(data: string) {
761    this.dataArray.push(data);
762  }
763
764  public reloadListener(): void {
765    this.listener?.onDataReloaded();
766  }
767
768  public registerDataChangeListener(listener: DataChangeListener): void {
769    this.listener = listener;
770  }
771
772  public unregisterDataChangeListener(): void {
773    this.listener = null;
774  }
775}
776
777class Params {
778  item: string = '';
779
780  constructor(item: string) {
781    this.item = item;
782  }
783}
784
785@Builder
786function buildNode(param: Params = new Params("hello")) {
787  ReusableChildComponent2({ item: param.item });
788}
789
790class MyNodeController extends NodeController {
791  public builderNode: BuilderNode<[Params]> | null = null;
792  public item: string = "";
793
794  makeNode(uiContext: UIContext): FrameNode | null {
795    if (this.builderNode == null) {
796      this.builderNode = new BuilderNode(uiContext, { selfIdealSize: { width: 300, height: 200 } });
797      this.builderNode.build(wrapBuilder<[Params]>(buildNode), new Params(this.item));
798    }
799    return this.builderNode.getFrameNode();
800  }
801}
802
803@Reusable
804@Component
805struct ReusableChildComponent {
806  @State item: string = '';
807  private controller: MyNodeController = new MyNodeController();
808
809  aboutToAppear() {
810    this.controller.item = this.item;
811  }
812
813  aboutToRecycle(): void {
814    console.log("ReusableChildComponent aboutToRecycle " + this.item);
815    this.controller?.builderNode?.recycle();
816  }
817
818  aboutToReuse(params: object): void {
819    console.log("ReusableChildComponent aboutToReuse " + JSON.stringify(params));
820    this.controller?.builderNode?.reuse(params);
821  }
822
823  build() {
824    NodeContainer(this.controller);
825  }
826}
827
828@Component
829struct ReusableChildComponent2 {
830  @Prop item: string = "false";
831
832  aboutToReuse(params: Record<string, object>) {
833    console.log("ReusableChildComponent2 Reusable 2 " + JSON.stringify(params));
834  }
835
836  aboutToRecycle(): void {
837    console.log("ReusableChildComponent2 aboutToRecycle 2 " + this.item);
838  }
839
840  build() {
841    Row() {
842      Text(this.item)
843        .fontSize(20)
844        .backgroundColor(Color.Yellow)
845        .margin({ left: 10 })
846    }.margin({ left: 10, right: 10 })
847  }
848}
849
850
851@Entry
852@Component
853struct Index {
854  @State data: MyDataSource = new MyDataSource();
855
856  aboutToAppear() {
857    for (let i = 0;i < 100; i++) {
858      this.data.pushData(i.toString());
859    }
860  }
861
862  build() {
863    Column() {
864      List({ space: 3 }) {
865        LazyForEach(this.data, (item: string) => {
866          ListItem() {
867            ReusableChildComponent({ item: item })
868          }
869        }, (item: string) => item)
870      }
871      .width('100%')
872      .height('100%')
873    }
874  }
875}
876```
877
878### updateConfiguration<sup>12+</sup>
879
880updateConfiguration(): void
881
882Updates the configuration of the entire node by passing in a [system environment change](../apis-ability-kit/js-apis-app-ability-configuration.md) event.
883
884**Atomic service API**: This API can be used in atomic services since API version 12.
885
886**System capability**: SystemCapability.ArkUI.ArkUI.Full
887
888> **NOTE**
889>
890> The **updateConfiguration** API is used to instruct an object to update, with the system environment used for the update being determined by the changes in the application's current system environment.
891
892**Example**
893```ts
894import { NodeController, BuilderNode, FrameNode, UIContext } from "@kit.ArkUI"
895import { AbilityConstant, Configuration, EnvironmentCallback } from '@kit.AbilityKit';
896
897class Params {
898  text: string = ""
899
900  constructor(text: string) {
901    this.text = text;
902  }
903}
904
905// Custom component
906@Component
907struct TextBuilder {
908  // The @Prop decorated attribute is the attribute to be updated in the custom component. It is a basic attribute.
909  @Prop message: string = "TextBuilder";
910
911  build() {
912    Row() {
913      Column() {
914        Text(this.message)
915          .fontSize(50)
916          .fontWeight(FontWeight.Bold)
917          .margin({ bottom: 36 })
918          .fontColor($r(`app.color.text_color`))
919          .backgroundColor($r(`app.color.start_window_background`))
920      }
921    }
922  }
923}
924
925@Builder
926function buildText(params: Params) {
927  Column() {
928    Text(params.text)
929      .fontSize(50)
930      .fontWeight(FontWeight.Bold)
931      .margin({ bottom: 36 })
932      .fontColor($r(`app.color.text_color`))
933    TextBuilder({ message: params.text }) // Custom component
934  }.backgroundColor($r(`app.color.start_window_background`))
935}
936
937class TextNodeController extends NodeController {
938  private textNode: BuilderNode<[Params]> | null = null;
939  private message: string = "";
940
941  constructor(message: string) {
942    super()
943    this.message = message;
944  }
945
946  makeNode(context: UIContext): FrameNode | null {
947    return this.textNode?.getFrameNode() ? this.textNode?.getFrameNode() : null;
948  }
949
950  createNode(context: UIContext) {
951    this.textNode = new BuilderNode(context);
952    this.textNode.build(wrapBuilder<[Params]>(buildText), new Params(this.message));
953    builderNodeMap.push(this.textNode);
954  }
955
956  deleteNode() {
957    let node = builderNodeMap.pop();
958    node?.dispose();
959  }
960
961  update(message: string) {
962    if (this.textNode !== null) {
963      // Call update to perform an update.
964      this.textNode.update(new Params(message));
965    }
966  }
967}
968
969// Record the created custom node object.
970const builderNodeMap: Array<BuilderNode<[Params]>> = new Array();
971
972function updateColorMode() {
973  builderNodeMap.forEach((value, index) => {
974    // Notify BuilderNode of the environment changes.
975    value.updateConfiguration();
976  })
977}
978
979@Entry
980@Component
981struct Index {
982  @State message: string = "hello"
983  private textNodeController: TextNodeController = new TextNodeController(this.message);
984  private count = 0;
985
986  aboutToAppear(): void {
987    let environmentCallback: EnvironmentCallback = {
988      onMemoryLevel: (level: AbilityConstant.MemoryLevel): void => {
989        console.log('onMemoryLevel');
990      },
991      onConfigurationUpdated: (config: Configuration): void => {
992        console.log('onConfigurationUpdated ' + JSON.stringify(config));
993        updateColorMode();
994      }
995    }
996    // Register a callback.
997    this.getUIContext().getHostContext()?.getApplicationContext().on('environment', environmentCallback);
998    // Create a custom node and add it to the map.
999    this.textNodeController.createNode(this.getUIContext());
1000  }
1001
1002  aboutToDisappear(): void {
1003    // Remove the reference to the custom node from the map and release the node.
1004    this.textNodeController.deleteNode();
1005  }
1006
1007  build() {
1008    Row() {
1009      Column() {
1010        NodeContainer(this.textNodeController)
1011          .width('100%')
1012          .height(200)
1013          .backgroundColor('#FFF0F0F0')
1014        Button('Update')
1015          .onClick(() => {
1016            this.count += 1;
1017            const message = "Update " + this.count.toString();
1018            this.textNodeController.update(message);
1019          })
1020      }
1021      .width('100%')
1022      .height('100%')
1023    }
1024    .height('100%')
1025  }
1026}
1027```
1028