1# Embedding ArkTS Components
2
3
4ArkUI on the native side offers a subset of ArkTS features, which excludes certain capabilities such as declarative UI syntax, custom struct components, and some advanced UI components.
5
6
7For scenarios requiring ArkTS-specific features, ArkUI provides a mechanism to embed ArkTS components using [ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md). This involves encapsulating ArkTS components and passing them to the native side, where they are converted into **ArkUI_NodeHandle** objects through the [OH_ArkUI_GetNodeHandleFromNapiValue](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_getnodehandlefromnapivalue) API for component mounting.
8
9
10> **NOTE**
11>
12> - **ArkUI_NodeHandle** objects obtained from **OH_ArkUI_GetNodeHandleFromNapiValue** are for child component parameters only, such as the second parameter of the [addChild](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#addchild) API. Using such objects in other scenarios, such as setting attributes with [setAttribute](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md#setattribute), will not take effect and will return an error code.
13>
14> - To modify ArkTS components on the native side, construct update data using Node-APIs, and then call the [update](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#update) API of **ComponentContent**.
15>
16> - During the process of [building custom components](ndk-build-custom-components.md), functions such as **measureNode** cannot be used to call components within the ArkTS module.
17
18
19The following example introduces the ArkTS **Refresh** component based on the [Integrating with ArkTS Pages](ndk-access-the-arkts-page.md) section.
20
21
22**Figure 1** Mounting a text list to a Refresh component
23
24![refresh_text_list](figures/refresh_text_list.gif)
25
26
271. Register the ArkTS component creation function to the native side for it to call, and use the **ComponentContent** capability to encapsulate the creation function.
28   ```ts
29   // MixedModule.ets
30   // Create ArkTS components using the ComponentContent capability.
31
32   import { NodeContent,  UIContext, RefreshModifier, ComponentContent } from '@kit.ArkUI';
33
34   // Define the data object for interaction between the native side and ArkTS.
35   interface NativeRefreshAttribute {
36     isRefreshing: boolean;
37     width?: number;
38     height?: number;
39     backgroundColor?: number;
40     refreshOffset?: number;
41     pullToRefresh?: boolean
42     onRefreshing?: () => void;
43     onOffsetChange?: (offset: number) => void;
44   }
45
46   // Define the format of the input parameters for the @Builder function.
47   interface RefreshAttribute {
48     isRefreshing: boolean;
49     // Optimize attribute settings for performance with Modifier.
50     modifier?: RefreshModifier;
51     slot?: NodeContent;
52     onRefreshing?: () => void;
53     onOffsetChange?: (offset: number) => void;
54   }
55
56   // ComponentContent encapsulates the ArkTS component dependency on the global @Builder function. You can nest @Component decorated custom components within the @Builder function when needed.
57   // The @Builder function provides a way of passing parameters, making it convenient to update parameters later through the update API of ComponentContent.
58   @Builder
59   function mixedRefresh(attribute: RefreshAttribute) {
60     Refresh({ refreshing: attribute.isRefreshing }) {
61       // As a container component, Refresh needs to use the ContentSlot mechanism to reserve a place for child components.
62       ContentSlot(attribute.slot)
63     }.attributeModifier(attribute.modifier)
64     .onRefreshing(() => {
65       console.info("on onRefreshing");
66       if (attribute.onRefreshing) {
67         console.info("on native onRefreshing");
68         attribute.onRefreshing();
69       }
70     })
71     .onOffsetChange((value: number) => {
72       console.info("on offset change: " + value);
73       if (attribute.onOffsetChange) {
74         console.info("on native onOffsetChange");
75         attribute.onOffsetChange(value);
76       }
77     })
78   }
79
80   // Define the return value of the creation function for interaction between the ArkTS side and the native side.
81   interface MixedModuleResult {
82     // Define the encapsulated object for the Refresh construction function, used by the native side to convert to an ArkUI_NodeHandle object.
83     content?: ComponentContent<RefreshAttribute>;
84     // As a container component, Refresh needs to use the ContentSlot mechanism to mount child components from the native side.
85     childSlot?: NodeContent;
86   }
87
88   // Provide an entry function for creating ArkTS components.
89   export function createMixedRefresh(value: NativeRefreshAttribute): MixedModuleResult {
90     console.info("createMixedRefresh");
91     // Use the AppStorage object to maintain the UI context object when the ability starts.
92     let uiContent = AppStorage.get<UIContext>("context");
93     let modifier = new RefreshModifier();
94     if (value.width) {
95       modifier.width(value.width)
96     }
97     if (value.height) {
98       modifier.height(value.height)
99     }
100     if (value.backgroundColor) {
101       modifier.backgroundColor(value.backgroundColor)
102     }
103     if (value.pullToRefresh) {
104       modifier.pullToRefresh(value.pullToRefresh)
105     }
106     if (value.refreshOffset) {
107       modifier.refreshOffset(value.refreshOffset)
108     }
109     // Create a NodeContent slot object for mounting Refresh child components.
110     let nodeSlot = new NodeContent();
111     // Create the Refresh component using ComponentContent and encapsulate it.
112     let content = new ComponentContent<RefreshAttribute>(uiContent!, wrapBuilder<[RefreshAttribute]>(mixedRefresh),
113       {
114         isRefreshing: value.isRefreshing,
115         modifier: modifier,
116         slot: nodeSlot,
117         onRefreshing: value.onRefreshing,
118         onOffsetChange: value.onOffsetChange
119       });
120     // Pass the encapsulated object of the Refresh component and its child component slot object to the native side.
121     return { content: content, childSlot: nodeSlot };
122   }
123
124   // Define the update function for the Refresh component for updating by the native side.
125   // In the update scenario, you need to return the encapsulated object of the Refresh component and its child component slot object to prevent the component from being re-created.
126   export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,
127     value: NativeRefreshAttribute): void {
128     let modifier = new RefreshModifier();
129     if (value.width) {
130       modifier.width(value.width)
131     }
132     if (value.height) {
133       modifier.height(value.height)
134     }
135     if (value.backgroundColor) {
136       modifier.backgroundColor(value.backgroundColor)
137     }
138     if (value.pullToRefresh) {
139       modifier.pullToRefresh(value.pullToRefresh)
140     }
141     if (value.refreshOffset) {
142       modifier.refreshOffset(value.refreshOffset)
143     }
144     // Call the update API of ComponentContent to update.
145     refresh.update({
146       isRefreshing: value.isRefreshing,
147       modifier: modifier,
148       slot: childSlot,
149       onRefreshing: value.onRefreshing,
150       onOffsetChange: value.onOffsetChange
151     })
152   }
153
154   ```
155
1562. Register the creation and update functions with the native side.
157   ```ts
158   // entry.ets
159   import nativeNode from 'libentry.so';
160   import { NodeContent } from '@kit.ArkUI';
161   import { createMixedRefresh, updateMixedRefresh } from './MixedModule'
162
163   @Entry
164   @Component
165   struct Index {
166     private rootSlot = new NodeContent();
167     @State @Watch('changeNativeFlag') showNative: boolean = false;
168
169     aboutToAppear(): void {
170       // Set the UI context.
171       AppStorage.setOrCreate<UIContext>("context", this.getUIContext());
172       // Set the builder function for mixed mode.
173       nativeNode.registerCreateMixedRefreshNode(createMixedRefresh);
174       nativeNode.registerUpdateMixedRefreshNode(updateMixedRefresh);
175     }
176
177     changeNativeFlag(): void {
178       if (this.showNative) {
179         // Create and mount the NativeModule component.
180         nativeNode.createNativeRoot(this.rootSlot)
181       } else {
182         // Destroy the NativeModule component.
183         nativeNode.destroyNativeRoot()
184       }
185     }
186
187     build() {
188       Column() {
189         Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {
190           this.showNative = !this.showNative
191         })
192         Row() {
193           // ArkTS inserts the native component.
194           ContentSlot(this.rootSlot)
195         }.layoutWeight(1)
196       }
197       .width('100%')
198       .height('100%')
199     }
200   }
201   ```
202
203   ```cpp
204   // native_init.cpp
205   #include "napi/native_api.h"
206   #include "ArkUIMixedRefresh.h"
207   #include "NativeEntry.h"
208
209   EXTERN_C_START
210   static napi_value Init(napi_env env, napi_value exports) {
211       napi_property_descriptor desc[] = {
212           {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},
213           // Register the mixed mode creation function.
214           {"registerCreateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterCreateRefresh, nullptr,
215            nullptr, nullptr, napi_default, nullptr},
216           // Register the mixed mode update function.
217           {"registerUpdateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterUpdateRefresh, nullptr,
218            nullptr, nullptr, napi_default, nullptr},
219           {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default,
220            nullptr}};
221       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
222       return exports;
223   }
224   EXTERN_C_END
225
226   static napi_module demoModule = {
227       .nm_version = 1,
228       .nm_flags = 0,
229       .nm_filename = nullptr,
230       .nm_register_func = Init,
231       .nm_modname = "entry",
232       .nm_priv = ((void *)0),
233       .reserved = {0},
234   };
235
236   extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
237   ```
238
2393. The native side saves the creation and update functions through the Node-API for subsequent calls.
240   ```c
241   // ArkUIMixedRefresh.h
242   // Mixed mode interaction class.
243
244   #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H
245   #define MYAPPLICATION_ARKUIMIXEDREFRESH_H
246
247   #include "ArkUIMixedNode.h"
248
249   #include <optional>
250
251   #include <arkui/native_node_napi.h>
252   #include <js_native_api_types.h>
253
254   namespace NativeModule {
255
256   class ArkUIMixedRefresh : public ArkUIMixedNode {
257   public:
258       static napi_value RegisterCreateRefresh(napi_env env, napi_callback_info info);
259       static napi_value RegisterUpdateRefresh(napi_env env, napi_callback_info info);
260   };
261
262   } // namespace NativeModule
263
264   #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H
265   ```
266
267   ```cpp
268   // ArkUIMixedRefresh.cpp
269   // Mixed mode interaction class.
270
271   #include "ArkUIMixedRefresh.h"
272   #include <hilog/log.h>
273
274   namespace NativeModule {
275   namespace {
276   napi_env g_env;
277   napi_ref g_createRefresh;
278   napi_ref g_updateRefresh;
279   } // namespace
280
281   napi_value ArkUIMixedRefresh::RegisterCreateRefresh(napi_env env, napi_callback_info info) {
282       size_t argc = 1;
283       napi_value args[1] = {nullptr};
284
285       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
286
287       g_env = env;
288       napi_ref refer;
289       // Save the reference after creation to prevent it from being released.
290       napi_create_reference(env, args[0], 1, &refer);
291
292       g_createRefresh = refer;
293       return nullptr;
294   }
295
296   napi_value ArkUIMixedRefresh::RegisterUpdateRefresh(napi_env env, napi_callback_info info) {
297       size_t argc = 1;
298       napi_value args[1] = {nullptr};
299
300       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
301
302       g_env = env;
303       napi_ref refer;
304       // Save the reference after creation to prevent it from being released.
305       napi_create_reference(env, args[0], 1, &refer);
306
307       g_updateRefresh = refer;
308       return nullptr;
309   }
310
311   } // namespace NativeModule
312   ```
313
3144. Abstract the base class of components in mixed mode for general logic management.
315   ```c
316   // ArkUIMixedNode.h
317   // Base class for mixed mode.
318
319   #ifndef MYAPPLICATION_ARKUIMIXEDNODE_H
320   #define MYAPPLICATION_ARKUIMIXEDNODE_H
321
322   #include <js_native_api.h>
323   #include <js_native_api_types.h>
324
325   #include "ArkUIBaseNode.h"
326   #include "NativeModule.h"
327
328   namespace NativeModule {
329
330   // Wrap ArkTS Node
331   class ArkUIMixedNode : public ArkUIBaseNode {
332   public:
333       ArkUIMixedNode(ArkUI_NodeHandle handle, napi_env env, napi_ref componentContent)
334           : ArkUIBaseNode(handle), env_(env), componentContent_(componentContent) {}
335
336       // In the base class destructor, the object on the ArkTS side in mixed mode needs to be released.
337       ~ArkUIMixedNode() override { napi_delete_reference(env_, componentContent_); }
338
339   protected:
340       napi_env env_;
341       napi_ref componentContent_;
342   };
343
344   } // namespace NativeModule
345
346   #endif // MYAPPLICATION_ARKUIMIXEDNODE_H
347   ```
348
3495. Implement the encapsulation object for the **Refresh** component in mixed mode.
350   ```c
351   // ArkUIMixedRefresh.h
352   // The encapsulation object of Refresh in mixed mode on the native side.
353
354   #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H
355   #define MYAPPLICATION_ARKUIMIXEDREFRESH_H
356
357   #include "ArkUIMixedNode.h"
358   #include "ArkUIBaseNode.h"
359
360   #include <optional>
361
362   #include <arkui/native_node_napi.h>
363   #include <js_native_api_types.h>
364
365   namespace NativeModule {
366
367   // Define the interaction data structure between the native side and the ArkTS side.
368   struct NativeRefreshAttribute {
369       std::optional<bool> isRefreshing;
370       std::optional<float> width;
371       std::optional<float> height;
372       std::optional<uint32_t> backgroundColor;
373       std::optional<float> refreshOffset;
374       std::optional<bool> pullToRefresh;
375       std::function<void()> onRefreshing;
376       std::function<void(float)> onOffsetChange;
377   };
378
379   class ArkUIMixedRefresh : public ArkUIMixedNode {
380   public:
381       // Call the ArkTS method to create the Refresh component.
382       static const std::shared_ptr<ArkUIMixedRefresh> Create(const NativeRefreshAttribute &attribute);
383
384       ArkUIMixedRefresh(ArkUI_NodeHandle handle, ArkUI_NodeContentHandle contentHandle, napi_env env,
385                         napi_ref componentContent, napi_ref nodeContent)
386           : ArkUIMixedNode(handle, env, componentContent), contentHandle_(contentHandle), nodeContent_(nodeContent) {}
387
388       ArkUIMixedRefresh() : ArkUIMixedNode(nullptr, nullptr, nullptr) {}
389
390       ~ArkUIMixedRefresh() override { napi_delete_reference(env_, nodeContent_); } // Release the placeholder component slot object for the child node.
391
392       void SetWidth(float width) { attribute_.width = width; }
393
394       void SetHeight(float height) { attribute_.height = height; }
395
396       void SetBackgroundColor(uint32_t color) { attribute_.backgroundColor = color; }
397
398       void SetRefreshState(bool isRefreshing) { attribute_.isRefreshing = isRefreshing; }
399
400       void SetPullToRefresh(bool pullToRefresh) { attribute_.pullToRefresh = pullToRefresh; }
401
402       void SetRefreshOffset(float offset) { attribute_.refreshOffset = offset; }
403
404       void SetRefreshCallback(const std::function<void()> &callback) { attribute_.onRefreshing = callback; }
405
406       void SetOnOffsetChange(const std::function<void(float)> &callback) { attribute_.onOffsetChange = callback; }
407
408       // To avoid frequent cross-language communication, cache property events on the native side and notify in batches.
409       void FlushMixedModeCmd();
410
411       static napi_value RegisterCreateRefresh(napi_env env, napi_callback_info info);
412       static napi_value RegisterUpdateRefresh(napi_env env, napi_callback_info info);
413
414   protected:
415       void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
416           assert(contentHandle_);
417           // Use NodeContent to mount the component (can be a transformation object of ArkTS on the native side through ComponentContent, or a pure native component) under the ArkTS component.
418           OH_ArkUI_NodeContent_AddNode(contentHandle_, child->GetHandle());
419       }
420
421       void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
422           assert(contentHandle_);
423           // Use NodeContent to remove the component.
424           OH_ArkUI_NodeContent_RemoveNode(contentHandle_, child->GetHandle());
425       }
426
427       void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override {
428           assert(contentHandle_);
429           // Use NodeContent to insert the component.
430           OH_ArkUI_NodeContent_InsertNode(contentHandle_, child->GetHandle(), index);
431       }
432
433   private:
434       // Use the Node-API to create the data structure on the ArkTS side.
435       static napi_value CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData);
436
437       ArkUI_NodeContentHandle contentHandle_;
438       napi_ref nodeContent_;
439       NativeRefreshAttribute attribute_;
440   };
441
442   } // namespace NativeModule
443
444   #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H
445   ```
446
447   Related implementation class description:
448
449   ```c
450   #include "ArkUIMixedRefresh.h"
451   #include <hilog/log.h>
452
453   namespace NativeModule {
454   namespace {
455   napi_env g_env;
456   napi_ref g_createRefresh;
457   napi_ref g_updateRefresh;
458   } // namespace
459
460   // Use the Node-API to create the data structure for interaction with the ArkTS side, used for the creation and update of the Refresh component.
461   napi_value ArkUIMixedRefresh::CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData) {
462       napi_property_descriptor desc[] = {
463           {"width", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
464           {"height", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
465           {"backgroundColor", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
466           {"pullToRefresh", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
467           {"isRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
468           {"refreshOffset", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
469           {"onRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
470           {"onOffsetChange", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
471       };
472       if (attribute.width) {
473           napi_value width;
474           napi_create_double(g_env, attribute.width.value(), &width);
475           desc[0].value = width;
476       }
477       if (attribute.height) {
478           napi_value height;
479           napi_create_double(g_env, attribute.height.value(), &height);
480           desc[1].value = height;
481       }
482       if (attribute.backgroundColor) {
483           napi_value backgroundColor;
484           napi_create_uint32(g_env, attribute.backgroundColor.value(), &backgroundColor);
485           desc[2].value = backgroundColor;
486       }
487       if (attribute.pullToRefresh) {
488           napi_value pullToRefresh;
489           napi_create_int32(g_env, attribute.pullToRefresh.value(), &pullToRefresh);
490           desc[3].value = pullToRefresh;
491       }
492       if (attribute.isRefreshing) {
493           napi_value isRefreshing;
494           napi_create_int32(g_env, attribute.isRefreshing.value(), &isRefreshing);
495           desc[4].value = isRefreshing;
496       }
497       if (attribute.refreshOffset) {
498           napi_value refreshOffset;
499           napi_create_double(g_env, attribute.refreshOffset.value(), &refreshOffset);
500           desc[5].value = refreshOffset;
501       }
502       if (attribute.onRefreshing) {
503           OH_LOG_INFO(LOG_APP, "onRefreshing start");
504           desc[6].method = [](napi_env env, napi_callback_info info) -> napi_value {
505               OH_LOG_INFO(LOG_APP, "onRefreshing callback");
506               size_t argc = 0;
507               napi_value args[0];
508               void *data;
509               napi_get_cb_info(env, info, &argc, args, nullptr, &data);
510               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data);
511               if (refresh && refresh->attribute_.onRefreshing) {
512                   refresh->attribute_.onRefreshing();
513               }
514               return nullptr;
515           };
516       }
517       if (attribute.onOffsetChange) {
518           OH_LOG_INFO(LOG_APP, "onOffsetChange start");
519           desc[7].method = [](napi_env env, napi_callback_info info) -> napi_value {
520               OH_LOG_INFO(LOG_APP, "onOffsetChange callback");
521               size_t argc = 1;
522               napi_value args[1] = {nullptr};
523               void *data;
524               napi_get_cb_info(env, info, &argc, args, nullptr, &data);
525               double offset = 0.0;
526               napi_get_value_double(env, args[0], &offset);
527               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data);
528               if (refresh && refresh->attribute_.onOffsetChange) {
529                   refresh->attribute_.onOffsetChange(offset);
530               }
531               return nullptr;
532           };
533       }
534       napi_value refreshAttribute = nullptr;
535       auto result = napi_create_object_with_properties(g_env, &refreshAttribute, sizeof(desc) / sizeof(desc[0]), desc);
536       if (result != napi_ok) {
537           return nullptr;
538       }
539       return refreshAttribute;
540   }
541
542   // Create the component on the ArkTS side and save it in the encapsulation object on the native side.
543   const std::shared_ptr<ArkUIMixedRefresh> ArkUIMixedRefresh::Create(const NativeRefreshAttribute &attribute) {
544       napi_handle_scope scope;
545       napi_open_handle_scope(g_env, &scope);
546       auto refresh = std::make_shared<ArkUIMixedRefresh>();
547       auto refreshAttribute = CreateRefreshAttribute(attribute, refresh.get());
548       if (refreshAttribute == nullptr) {
549           napi_close_handle_scope(g_env, scope);
550           return nullptr;
551       }
552       napi_value result = nullptr;
553       napi_value argv[1] = {refreshAttribute};
554       napi_value createRefresh = nullptr;
555       napi_get_reference_value(g_env, g_createRefresh, &createRefresh);
556       // Call the ArkTS Create function to create the ArkTS ComponentContent.
557       napi_call_function(g_env, nullptr, createRefresh, 1, argv, &result);
558
559       // Obtain the ArkTS Refresh component.
560       napi_value componentContent = nullptr;
561       napi_get_named_property(g_env, result, "content", &componentContent);
562       ArkUI_NodeHandle handle;
563       OH_ArkUI_GetNodeHandleFromNapiValue(g_env, componentContent, &handle);
564       assert(handle);
565       // Obtain the child component slot of the ArkTS Refresh component.
566       napi_value nodeContent = nullptr;
567       napi_get_named_property(g_env, result, "childSlot", &nodeContent);
568       ArkUI_NodeContentHandle contentHandle;
569       OH_ArkUI_GetNodeContentFromNapiValue(g_env, nodeContent, &contentHandle);
570       assert(contentHandle);
571       // Save the ArkTS ComponentContent to prevent the object on the ArkTS side from being released and for subsequent updates.
572       napi_ref componentContentRef;
573       napi_create_reference(g_env, componentContent, 1, &componentContentRef);
574       // Save the ArkTS NodeContent to prevent the object on the ArkTS side from being released and for subsequent updates.
575       napi_ref nodeContentRef;
576       napi_create_reference(g_env, nodeContent, 1, &nodeContentRef);
577       // Update the Refresh component related parameters.
578       refresh->handle_ = handle;
579       refresh->env_ = g_env;
580       refresh->componentContent_ = componentContentRef;
581       refresh->nodeContent_ = nodeContentRef;
582       refresh->contentHandle_ = contentHandle;
583       refresh->attribute_ = attribute;
584       return refresh;
585   }
586   // Implementation of the update function.
587   void ArkUIMixedRefresh::FlushMixedModeCmd() {
588       napi_handle_scope scope;
589       napi_open_handle_scope(g_env, &scope);
590       // Create the input parameters for the call to the ArkTS API.
591       auto refreshAttribute = CreateRefreshAttribute(attribute_, this);
592       if (refreshAttribute == nullptr) {
593           napi_close_handle_scope(g_env, scope);
594           return;
595       }
596       // Obtain the remaining two API parameters for the update API.
597       napi_value componentContent = nullptr;
598       napi_get_reference_value(g_env, componentContent_, &componentContent);
599       napi_value nodeContent = nullptr;
600       napi_get_reference_value(g_env, nodeContent_, &nodeContent);
601
602       napi_value argv[3] = {componentContent, nodeContent, refreshAttribute};
603       napi_value updateRefresh = nullptr;
604       napi_get_reference_value(g_env, g_updateRefresh, &updateRefresh);
605       // Call the ArkTS Update function to update.
606       napi_value result = nullptr;
607       napi_call_function(g_env, nullptr, updateRefresh, 3, argv, &result);
608   }
609
610   napi_value ArkUIMixedRefresh::RegisterCreateRefresh(napi_env env, napi_callback_info info) {
611       size_t argc = 1;
612       napi_value args[1] = {nullptr};
613
614       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
615
616       g_env = env;
617       napi_ref refer;
618       napi_create_reference(env, args[0], 1, &refer);
619
620       g_createRefresh = refer;
621       return nullptr;
622   }
623
624   napi_value ArkUIMixedRefresh::RegisterUpdateRefresh(napi_env env, napi_callback_info info) {
625       size_t argc = 1;
626       napi_value args[1] = {nullptr};
627
628       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
629
630       g_env = env;
631       napi_ref refer;
632       napi_create_reference(env, args[0], 1, &refer);
633
634       g_updateRefresh = refer;
635       return nullptr;
636   }
637
638   } // namespace NativeModule
639
640   ```
641
6426. Use the page structure from the [Integrating with ArkTS Page](ndk-access-the-arkts-page.md) section, and continue with the [timer module simple implementation](ndk-loading-long-list.md), making the **Refresh** component the parent component of the text list.
643   ```c
644   // MixedRefreshExample.h
645   // Sample code for mixed mode.
646
647   #ifndef MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
648   #define MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
649
650   #include "ArkUIBaseNode.h"
651   #include "ArkUIMixedRefresh.h"
652   #include "TextListExample.h"
653   #include "UITimer.h"
654
655   #include <js_native_api_types.h>
656
657   namespace NativeModule {
658
659   std::shared_ptr<ArkUIBaseNode> CreateMixedRefreshList(napi_env env) {
660       auto list = CreateTextListExample();
661       // Create the Refresh component in mixed mode and mount the List component.
662       NativeRefreshAttribute nativeRefreshAttribute{
663           .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true};
664       auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute);
665       refresh->AddChild(list);
666
667       // Set the event for mixed mode.
668       refresh->SetOnOffsetChange(
669           [](float offset) { OH_LOG_INFO(LOG_APP, "on refresh offset changed: %{public}f", offset); });
670       refresh->SetRefreshCallback([refreshPtr = refresh.get(), env]() {
671           OH_LOG_INFO(LOG_APP, "on refreshing");
672           // Start the timer to simulate data acquisition.
673           CreateNativeTimer(env, refreshPtr, 1, [](void *userData, int32_t count) {
674               // Disable the refresh feature after data is obtained.
675               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(userData);
676               refresh->SetRefreshState(false);
677               refresh->FlushMixedModeCmd();
678           });
679       });
680
681       // Update the event to the ArkTS side.
682       refresh->FlushMixedModeCmd();
683       return refresh;
684   }
685
686   } // namespace NativeModule
687
688   #endif // MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
689   ```
690
691   Replace the entry component creation with the pull-to-refresh text list.
692
693   ```c
694   #include "NativeEntry.h"
695
696   #include "ArkUIMixedRefresh.h"
697   #include "MixedRefreshExample.h"
698   #include "TextListExample.h"
699
700   #include <arkui/native_node_napi.h>
701   #include <arkui/native_type.h>
702   #include <js_native_api.h>
703   #include <uv.h>
704
705   namespace NativeModule {
706
707   napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {
708       size_t argc = 1;
709       napi_value args[1] = {nullptr};
710
711       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
712
713       // Obtain NodeContent.
714       ArkUI_NodeContentHandle contentHandle;
715       OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
716       NativeEntry::GetInstance()->SetContentHandle(contentHandle);
717
718       // Create a Refresh text list.
719       auto refresh = CreateMixedRefreshList(env);
720
721       // Keep the native side object in the management class to maintain its lifecycle.
722       NativeEntry::GetInstance()->SetRootNode(refresh);
723       return nullptr;
724   }
725
726   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
727       // Release the native side object from the management class.
728       NativeEntry::GetInstance()->DisposeRootNode();
729       return nullptr;
730   }
731
732   } // namespace NativeModule
733
734   ```
735