1# Custom Component Lifecycle 2 3The lifecycle callbacks of a custom component are used to notify users of the lifecycle of the component. These callbacks are private and are invoked by the development framework at a specified time at runtime. They cannot be manually invoked from applications. Do not reuse the same custom component node across multiple windows, as otherwise its lifecycle may become disrupted. 4 5>**NOTE** 6> 7>- The initial APIs of this module are supported since API version 7. Newly added APIs will be marked with a superscript to indicate their earliest API version. 8>- Promise and asynchronous callback functions can be used in lifecycle functions, for example, network resource getters and timer setters. 9 10 11## aboutToAppear 12 13aboutToAppear?(): void 14 15Invoked after a new instance of the custom component is created and before its **build()** function is executed. You can change state variables in **aboutToAppear**. The change will take effect when you execute the **build()** function next time. The **aboutToAppear** lifecycle callback of a custom component with a custom layout is invoked during the layout process. 16 17> **NOTE** 18> 19> * In this callback function, it is recommended that you only perform initialization logic for the current node component. Avoid high-time-consuming operations that may block the main thread. For high-time-consuming operations, consider caching or asynchronous solutions. For best practices, see [Optimizing Performance of UI Components: Avoiding Time-Consuming Operations During the Lifecycle of Custom Components](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-ui-component-performance-optimization#section18755173594714). 20> * In scenarios where components need to be frequently created and destroyed, this callback will be called frequently. For best practices, see [Optimizing Time-Consuming Operations in the Main Thread: Component Lifecycle Callback](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-time-optimization-of-the-main-thread#section418843713435). 21 22**Widget capability**: This API can be used in ArkTS widgets since API version 9. 23 24**Atomic service API**: This API can be used in atomic services since API version 11. 25 26**System capability**: SystemCapability.ArkUI.ArkUI.Full 27 28## onDidBuild<sup>12+</sup> 29 30onDidBuild?(): void 31 32Invoked after the **build()** function of the custom component is executed. You can use this callback for actions that do not directly affect the UI, such as tracking data reporting. Do not change state variables or use functions (such as **animateTo**) in **onDidBuild**. Otherwise, unstable UI performance may result. 33 34**Atomic service API**: This API can be used in atomic services since API version 12. 35 36**System capability**: SystemCapability.ArkUI.ArkUI.Full 37 38## aboutToDisappear 39 40aboutToDisappear?(): void 41 42Invoked when this component is about to disappear. Do not change state variables in the **aboutToDisappear** function as doing this can cause unexpected errors. For example, the modification of the **@Link** decorated variable may cause unstable application running. 43 44> **NOTE** 45> 46> In scenarios where components need to be frequently created and destroyed, this callback will be called frequently. For best practices, see [Optimizing Time-Consuming Operations in the Main Thread: Component Lifecycle Callback](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-time-optimization-of-the-main-thread#section418843713435). 47 48**Widget capability**: This API can be used in ArkTS widgets since API version 9. 49 50**Atomic service API**: This API can be used in atomic services since API version 11. 51 52**System capability**: SystemCapability.ArkUI.ArkUI.Full 53 54## onPageShow 55 56onPageShow?(): void 57 58Triggered each time a router-managed page (only custom components decorated with [\@Entry](../../../../application-dev/ui/state-management/arkts-create-custom-components.md#entry)) is displayed, including scenarios such as route navigation and the application returning to the foreground. 59 60**Atomic service API**: This API can be used in atomic services since API version 11. 61 62**System capability**: SystemCapability.ArkUI.ArkUI.Full 63 64## onPageHide 65 66onPageHide?(): void 67 68Triggered each time a router-managed page (only custom components decorated with [\@Entry](../../../../application-dev/ui/state-management/arkts-create-custom-components.md#entry)) is hidden, including scenarios such as route navigation and the application moving to background. 69 70> **NOTE** 71> 72> To ensure smooth UI responsiveness, avoid executing time-consuming operations within the callback function that may block the main thread. For resource-intensive tasks such as camera resource deallocation, consider implementing asynchronous solutions. For best practices, see [Reducing Application Latency: Postponing Resource Release](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-application-latency-optimization-cases#section8783201923819). 73 74**Atomic service API**: This API can be used in atomic services since API version 11. 75 76**System capability**: SystemCapability.ArkUI.ArkUI.Full 77 78## onBackPress 79 80onBackPress?(): void | boolean 81 82Triggered when the user clicks the back button (only effective for router-managed pages). The value **true** means that the page executes its own return logic, and **false** (default) means that the default return logic is used. 83 84**Atomic service API**: This API can be used in atomic services since API version 11. 85 86**System capability**: SystemCapability.ArkUI.ArkUI.Full 87 88**Return value** 89 90| Type | Description | 91| ------------------- | --------- | 92| void \| boolean | Action of the back button. The value **true** means that the page executes its own return logic, and **false** (default) means that the default return logic is used.| 93 94```ts 95// xxx.ets 96@Entry 97@Component 98struct IndexComponent { 99 @State textColor: Color = Color.Black; 100 101 onPageShow() { 102 this.textColor = Color.Blue; 103 console.info('IndexComponent onPageShow'); 104 } 105 106 onPageHide() { 107 this.textColor = Color.Transparent; 108 console.info('IndexComponent onPageHide'); 109 } 110 111 onBackPress() { 112 this.textColor = Color.Red; 113 console.info('IndexComponent onBackPress'); 114 } 115 116 build() { 117 Column() { 118 Text('Hello World') 119 .fontColor(this.textColor) 120 .fontSize(30) 121 .margin(30) 122 }.width('100%') 123 } 124} 125``` 126 127 128## onNewParam<sup>19+</sup> 129 130onNewParam?(param: ESObject): void 131 132Triggered when a page previously existing in the navigation stack is brought to the top through navigation in [single-instance](../js-apis-router.md#routermode9) mode. It is only effective for custom components decorated with [\@Entry](../../../../application-dev/ui/state-management/arkts-create-custom-components.md#entry) that serve as [router-managed](../js-apis-router.md) pages. 133 134**Atomic service API**: This API can be used in atomic services since API version 19. 135 136**System capability**: SystemCapability.ArkUI.ArkUI.Full 137 138**Parameters** 139 140| Name| Type | Description | 141|-------|----------|---------------------------| 142| param | ESObject | Data passed to the target page during redirection.| 143 144```ts 145// pages/Index.ets 146import { router } from '@kit.ArkUI'; 147 148export class routerParam { 149 msg: string = '__NA__'; 150 151 constructor(msg: string) { 152 this.msg = msg; 153 } 154} 155 156@Entry 157@Component 158struct Index { 159 aboutToAppear(): void { 160 console.log('onNewParam', 'Index aboutToAppear'); 161 } 162 163 onNewParam(param: ESObject) { 164 console.log('onNewParam', 'Index onNewParam, param: ' + JSON.stringify(param)); 165 } 166 167 build() { 168 Column() { 169 Button('push pageOne Standard') 170 .margin(10) 171 .onClick(() => { 172 this.getUIContext().getRouter().pushUrl({ 173 url: 'pages/PageOne', 174 params: new routerParam('push pageOne Standard') 175 }, router.RouterMode.Standard); 176 }) 177 Button('push pageOne Single') 178 .margin(10) 179 .onClick(() => { 180 this.getUIContext().getRouter().pushUrl({ 181 url: 'pages/PageOne', 182 params: new routerParam('push pageOne Single') 183 }, router.RouterMode.Single) 184 }) 185 } 186 .width('100%') 187 .height('100%') 188 } 189} 190``` 191<!--code_no_check--> 192```ts 193// pages/PageOne.ets 194import { router } from '@kit.ArkUI'; 195import { routerParam } from './Index'; 196 197@Entry 198@Component 199struct PageOne { 200 aboutToAppear(): void { 201 console.log('onNewParam', 'PageOne aboutToAppear'); 202 } 203 204 onNewParam(param: ESObject) { 205 console.log('onNewParam', 'PageOne onNewParam, param: ' + JSON.stringify(param)); 206 } 207 208 build() { 209 Column() { 210 Button('push Index Standard') 211 .margin(10) 212 .onClick(() => { 213 this.getUIContext().getRouter().pushUrl({ 214 url: 'pages/Index', 215 params: new routerParam('push Index Standard') 216 }, router.RouterMode.Standard); 217 }) 218 Button('push Index Single') 219 .margin(10) 220 .onClick(() => { 221 this.getUIContext().getRouter().pushUrl({ 222 url: 'pages/Index', 223 params: new routerParam('push Index Single') 224 }, router.RouterMode.Single) 225 }) 226 } 227 .width('100%') 228 .height('100%') 229 } 230} 231``` 232 233## aboutToReuse<sup>10+</sup> 234 235aboutToReuse?(params: Record\<string, Object | undefined | null>): void 236 237Invoked when a reusable custom component is re-added to the node tree from the reuse cache to receive construction parameters of the component. 238 239> **NOTE** 240> 241> * Avoid repeatedly updating state variables that are automatically updated, such as @Link, @ObjectLink, and @Prop decorated variables, within **aboutToReuse**. For best practices, see [Component Reuse: Avoiding Repeated Assignment of Automatically Updated State Variables in aboutToReuse()](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-component-reuse#section7441712174414). 242> * In scrolling scenarios where component reuse is implemented, this callback is typically required to update the component's state variables. As such, avoid performing time-consuming operations within this callback to prevent frame drops and UI stuttering during scrolling animations. For best practices, see [Optimizing Time-Consuming Operations in the Main Thread: Component Reuse Callback](https://developer.huawei.com/consumer/en/doc/best-practices/bpta-time-optimization-of-the-main-thread#section20815336174316). 243 244**Atomic service API**: This API can be used in atomic services since API version 11. 245 246**System capability**: SystemCapability.ArkUI.ArkUI.Full 247 248**Parameters** 249 250| Name | Type | Description | 251|--------|-------------------------------------------|---------------------| 252| params | Record\<string, Object \| undefined \| null> | Construction parameters of the custom component.| 253 254```ts 255// xxx.ets 256export class Message { 257 value: string | undefined; 258 259 constructor(value: string) { 260 this.value = value 261 } 262} 263 264@Entry 265@Component 266struct Index { 267 @State switch: boolean = true 268 269 build() { 270 Column() { 271 Button('Hello World') 272 .fontSize(50) 273 .fontWeight(FontWeight.Bold) 274 .onClick(() => { 275 this.switch = !this.switch 276 }) 277 if (this.switch) { 278 Child({ message: new Message('Child') }) 279 } 280 } 281 .height("100%") 282 .width('100%') 283 } 284} 285 286@Reusable 287@Component 288struct Child { 289 @State message: Message = new Message('AboutToReuse'); 290 291 aboutToReuse(params: Record<string, ESObject>) { 292 console.info("Recycle Child") 293 this.message = params.message as Message 294 } 295 296 build() { 297 Column() { 298 Text(this.message.value) 299 .fontSize(20) 300 } 301 .borderWidth(2) 302 .height(100) 303 } 304} 305``` 306 307## aboutToReuse<sup>18+</sup> 308 309aboutToReuse?(): void 310 311Invoked when a reusable custom component managed by state management V2 is taken from the reuse pool and reinserted into the node tree. 312 313For details, see [\@ReusableV2](../../../ui/state-management/arkts-new-reusableV2.md). 314 315**Atomic service API**: This API can be used in atomic services since API version 18. 316 317**System capability**: SystemCapability.ArkUI.ArkUI.Full 318 319```ts 320@Entry 321@ComponentV2 322struct Index { 323 @Local condition: boolean = true; 324 build() { 325 Column() { 326 Button('Recycle/Reuse').onClick(()=>{this.condition=!this.condition;}) // Click to switch the recycle/reuse state. 327 if (this.condition) { 328 ReusableV2Component() 329 } 330 } 331 } 332} 333@ReusableV2 334@ComponentV2 335struct ReusableV2Component { 336 @Local message: string = 'Hello World'; 337 aboutToReuse() { 338 console.log('ReusableV2Component aboutToReuse'); // Called when a component is reused. 339 } 340 build() { 341 Column() { 342 Text(this.message) 343 } 344 } 345} 346``` 347 348 349## aboutToRecycle<sup>10+</sup> 350 351aboutToRecycle?(): void 352 353Invoked when this reusable component is about to be added from the component tree to the reuse cache. 354 355**Atomic service API**: This API can be used in atomic services since API version 11. 356 357**System capability**: SystemCapability.ArkUI.ArkUI.Full 358 359```ts 360// xxx.ets 361export class Message { 362 value: string | undefined; 363 364 constructor(value: string) { 365 this.value = value; 366 } 367} 368 369@Entry 370@Component 371struct Index { 372 @State switch: boolean = true; 373 374 build() { 375 Column() { 376 Button('Hello World') 377 .fontSize(50) 378 .fontWeight(FontWeight.Bold) 379 .onClick(() => { 380 this.switch = !this.switch; 381 }) 382 if (this.switch) { 383 Child({ message: new Message('Child') }) 384 } 385 } 386 .height("100%") 387 .width('100%') 388 } 389} 390 391@Reusable 392@Component 393struct Child { 394 @State message: Message = new Message('AboutToReuse'); 395 396 aboutToReuse(params: Record<string, ESObject>) { 397 console.info("Reuse Child"); 398 this.message = params.message as Message; 399 } 400 401 aboutToRecycle() { 402 // This is where you can release memory-intensive content or other non-essential resource references to avoid continuous memory usage that could lead to memory leaks. 403 console.info("The child enters the recycle pool."); 404 } 405 406 build() { 407 Column() { 408 Text(this.message.value) 409 .fontSize(20) 410 } 411 .borderWidth(2) 412 .height(100) 413 } 414} 415``` 416 417## onWillApplyTheme<sup>12+</sup> 418 419onWillApplyTheme?(theme: Theme): void 420 421Invoked before the **build()** function of a new instance of the custom component is executed, to obtain the **Theme** object of the component context. You can change state variables in **onWillApplyTheme**. The change will take effect when you execute the **build()** function next time. 422 423> **NOTE** 424> 425> Since API version 18, this API is supported in the components of V2. 426 427**Atomic service API**: This API can be used in atomic services since API version 12. 428 429**System capability**: SystemCapability.ArkUI.ArkUI.Full 430 431**Parameters** 432 433| Name | Type | Description | 434|--------|------------------------------------------|------------| 435| theme | [Theme](../js-apis-arkui-theme.md#theme) | Current theme object of the custom component.| 436 437V1: 438 439```ts 440// xxx.ets 441import { CustomTheme, CustomColors, Theme, ThemeControl } from '@kit.ArkUI'; 442 443class BlueColors implements CustomColors { 444 fontPrimary = Color.White; 445 backgroundPrimary = Color.Blue; 446 brand = Color.Blue; // Brand color 447} 448 449class PageCustomTheme implements CustomTheme { 450 colors?: CustomColors; 451 452 constructor(colors: CustomColors) { 453 this.colors = colors; 454 } 455} 456const BlueColorsTheme = new PageCustomTheme(new BlueColors()); 457// setDefaultTheme should be called on the application entry page or in an ability. 458ThemeControl.setDefaultTheme(BlueColorsTheme); 459 460@Entry 461@Component 462struct IndexComponent { 463 @State textColor: ResourceColor = $r('sys.color.font_primary'); 464 @State columBgColor: ResourceColor = $r('sys.color.background_primary'); 465 466 // Obtain the Theme object of the current component context. Set textColor and columBgColor in onWillApplyTheme to the color (BlueColorsTheme) of the Theme object in use. 467 onWillApplyTheme(theme: Theme) { 468 this.textColor = theme.colors.fontPrimary; 469 this.columBgColor = theme.colors.backgroundPrimary; 470 console.info('IndexComponent onWillApplyTheme'); 471 } 472 473 build() { 474 Column() { 475 // Initial color style of the component 476 Column() { 477 Text('Hello World') 478 .fontColor($r('sys.color.font_primary')) 479 .fontSize(30) 480 } 481 .width('100%') 482 .height('25%') 483 .borderRadius('10vp') 484 .backgroundColor($r('sys.color.background_primary')) 485 486 // The color style configured in onWillApplyTheme is applied. 487 Column() { 488 Text('onWillApplyTheme') 489 .fontColor(this.textColor) 490 .fontSize(30) 491 Text('Hello World') 492 .fontColor(this.textColor) 493 .fontSize(30) 494 } 495 .width('100%') 496 .height('25%') 497 .borderRadius('10vp') 498 .backgroundColor(this.columBgColor) 499 } 500 .padding('16vp') 501 .backgroundColor('#dcdcdc') 502 .width('100%') 503 .height('100%') 504 } 505} 506``` 507 508 509V2: 510 511```ts 512import { CustomTheme, CustomColors, Theme, ThemeControl } from '@kit.ArkUI'; 513 514class BlueColors implements CustomColors { 515 fontPrimary = Color.White; 516 backgroundPrimary = Color.Blue; 517 brand = Color.Blue; // Brand color 518} 519 520class PageCustomTheme implements CustomTheme { 521 colors?: CustomColors; 522 523 constructor(colors: CustomColors) { 524 this.colors = colors; 525 } 526} 527 528const BlueColorsTheme = new PageCustomTheme(new BlueColors()); 529// setDefaultTheme should be called on the application entry page or in an ability. 530ThemeControl.setDefaultTheme(BlueColorsTheme); 531 532@Entry 533@ComponentV2 534struct IndexComponent { 535 @Local textColor: ResourceColor = $r('sys.color.font_primary'); 536 @Local columBgColor: ResourceColor = $r('sys.color.background_primary'); 537 538 // Obtain the Theme object of the current component context. Set textColor and columBgColor in onWillApplyTheme to the color (BlueColorsTheme) of the Theme object in use. 539 onWillApplyTheme(theme: Theme) { 540 this.textColor = theme.colors.fontPrimary; 541 this.columBgColor = theme.colors.backgroundPrimary; 542 console.info('IndexComponent onWillApplyTheme'); 543 } 544 545 build() { 546 Column() { 547 // Initial color style of the component 548 Column() { 549 Text('Hello World') 550 .fontColor($r('sys.color.font_primary')) 551 .fontSize(30) 552 } 553 .width('100%') 554 .height('25%') 555 .borderRadius('10vp') 556 .backgroundColor($r('sys.color.background_primary')) 557 558 // The color style configured in onWillApplyTheme is applied. 559 Column() { 560 Text('onWillApplyTheme') 561 .fontColor(this.textColor) 562 .fontSize(30) 563 Text('Hello World') 564 .fontColor(this.textColor) 565 .fontSize(30) 566 } 567 .width('100%') 568 .height('25%') 569 .borderRadius('10vp') 570 .backgroundColor(this.columBgColor) 571 } 572 .padding('16vp') 573 .backgroundColor('#dcdcdc') 574 .width('100%') 575 .height('100%') 576 } 577} 578``` 579 580 581