1e41f4b71Sopenharmony_ci# Freezing a Custom Component 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciWhen a custom component is inactive, it can be frozen so that its state variable does not respond to updates. That is, the @Watch decorated method is not called, and the node associated with the state variable is not re-rendered. You can use the **freezeWhenInactive** attribute to specify whether to freeze a custom component. If no parameter is passed in, the feature is disabled. This feature works in following scenarios: page routing, **\<TabContent>**, **LazyForEach**, and **\<Navigation>**. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci 6e41f4b71Sopenharmony_ci> **NOTE** 7e41f4b71Sopenharmony_ci> 8e41f4b71Sopenharmony_ci> Custom component freezing is supported since API version 11. 9e41f4b71Sopenharmony_ci 10e41f4b71Sopenharmony_ci## Use Scenarios 11e41f4b71Sopenharmony_ci 12e41f4b71Sopenharmony_ci### Page Routing 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci- When page A calls the **router.pushUrl** API to jump to page B, page A is hidden and invisible. In this case, if the state variable on page A is updated, page A is not re-rendered. 15e41f4b71Sopenharmony_ci 16e41f4b71Sopenharmony_ci- The freezing feature does not work when the application is running in the background. 17e41f4b71Sopenharmony_ci 18e41f4b71Sopenharmony_ciPage A: 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci```ts 21e41f4b71Sopenharmony_ciimport { router } from '@kit.ArkUI'; 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci@Entry 24e41f4b71Sopenharmony_ci@Component({ freezeWhenInactive: true }) 25e41f4b71Sopenharmony_cistruct FirstTest { 26e41f4b71Sopenharmony_ci @StorageLink('PropA') @Watch("first") storageLink: number = 47; 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci first() { 29e41f4b71Sopenharmony_ci console.info("first page " + `${this.storageLink}`) 30e41f4b71Sopenharmony_ci } 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci build() { 33e41f4b71Sopenharmony_ci Column() { 34e41f4b71Sopenharmony_ci Text(`From fist Page ${this.storageLink}`).fontSize(50) 35e41f4b71Sopenharmony_ci Button('first page storageLink + 1').fontSize(30) 36e41f4b71Sopenharmony_ci .onClick(() => { 37e41f4b71Sopenharmony_ci this.storageLink += 1 38e41f4b71Sopenharmony_ci }) 39e41f4b71Sopenharmony_ci Button('go to next page').fontSize(30) 40e41f4b71Sopenharmony_ci .onClick(() => { 41e41f4b71Sopenharmony_ci router.pushUrl({ url: 'pages/second' }) 42e41f4b71Sopenharmony_ci }) 43e41f4b71Sopenharmony_ci } 44e41f4b71Sopenharmony_ci } 45e41f4b71Sopenharmony_ci} 46e41f4b71Sopenharmony_ci``` 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ciPage B: 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ci```ts 51e41f4b71Sopenharmony_ciimport { router } from '@kit.ArkUI'; 52e41f4b71Sopenharmony_ci 53e41f4b71Sopenharmony_ci@Entry 54e41f4b71Sopenharmony_ci@Component({ freezeWhenInactive: true }) 55e41f4b71Sopenharmony_cistruct SecondTest { 56e41f4b71Sopenharmony_ci @StorageLink('PropA') @Watch("second") storageLink2: number = 1; 57e41f4b71Sopenharmony_ci 58e41f4b71Sopenharmony_ci second() { 59e41f4b71Sopenharmony_ci console.info("second page: " + `${this.storageLink2}`) 60e41f4b71Sopenharmony_ci } 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci build() { 63e41f4b71Sopenharmony_ci Column() { 64e41f4b71Sopenharmony_ci 65e41f4b71Sopenharmony_ci Text(`second Page ${this.storageLink2}`).fontSize(50) 66e41f4b71Sopenharmony_ci Button('Change Divider.strokeWidth') 67e41f4b71Sopenharmony_ci .onClick(() => { 68e41f4b71Sopenharmony_ci router.back() 69e41f4b71Sopenharmony_ci }) 70e41f4b71Sopenharmony_ci 71e41f4b71Sopenharmony_ci Button('second page storageLink2 + 2').fontSize(30) 72e41f4b71Sopenharmony_ci .onClick(() => { 73e41f4b71Sopenharmony_ci this.storageLink2 += 2 74e41f4b71Sopenharmony_ci }) 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci } 77e41f4b71Sopenharmony_ci } 78e41f4b71Sopenharmony_ci} 79e41f4b71Sopenharmony_ci``` 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ciIn the preceding example: 82e41f4b71Sopenharmony_ci 83e41f4b71Sopenharmony_ci1. When the button **first page storageLink + 1** on page A is clicked, the **storageLink** state variable is updated, and the @Watch decorated **first** method is called. 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci2. Through **router.pushUrl({url:'pages/second'})**, page B is displayed, and page A is hidden with its state changing from active to inactive. 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci3. When the button **this.storageLink2 += 2** on page B is clicked, only the @Watch decorated **second** method of page B is called, because page A has been frozen when inactive. 88e41f4b71Sopenharmony_ci 89e41f4b71Sopenharmony_ci4. When the **back** button is clicked, page B is destroyed, and page A changes from inactive to active. At this time, if the state variable of page A is updated, the @Watch decorated **first** method of page A is called again. 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci 92e41f4b71Sopenharmony_ci### TabContent 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci- You can freeze invisible **TabContent** components in the **Tabs** container so that they do not trigger UI re-rendering. 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci- During initial rendering, only the **TabContent** component that is being displayed is created. All **TabContent** components are created only after all of them have been switched to. 97e41f4b71Sopenharmony_ci 98e41f4b71Sopenharmony_ci```ts 99e41f4b71Sopenharmony_ci@Entry 100e41f4b71Sopenharmony_ci@Component 101e41f4b71Sopenharmony_cistruct TabContentTest { 102e41f4b71Sopenharmony_ci @State @Watch("onMessageUpdated") message: number = 0; 103e41f4b71Sopenharmony_ci private data: number[] = [0, 1] 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci onMessageUpdated() { 106e41f4b71Sopenharmony_ci console.info(`TabContent message callback func ${this.message}`) 107e41f4b71Sopenharmony_ci } 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci build() { 110e41f4b71Sopenharmony_ci Row() { 111e41f4b71Sopenharmony_ci Column() { 112e41f4b71Sopenharmony_ci Button('change message').onClick(() => { 113e41f4b71Sopenharmony_ci this.message++ 114e41f4b71Sopenharmony_ci }) 115e41f4b71Sopenharmony_ci 116e41f4b71Sopenharmony_ci Tabs() { 117e41f4b71Sopenharmony_ci ForEach(this.data, (item: number) => { 118e41f4b71Sopenharmony_ci TabContent() { 119e41f4b71Sopenharmony_ci FreezeChild({ message: this.message, index: item }) 120e41f4b71Sopenharmony_ci }.tabBar(`tab${item}`) 121e41f4b71Sopenharmony_ci }, (item: number) => item.toString()) 122e41f4b71Sopenharmony_ci } 123e41f4b71Sopenharmony_ci } 124e41f4b71Sopenharmony_ci .width('100%') 125e41f4b71Sopenharmony_ci } 126e41f4b71Sopenharmony_ci .height('100%') 127e41f4b71Sopenharmony_ci } 128e41f4b71Sopenharmony_ci} 129e41f4b71Sopenharmony_ci 130e41f4b71Sopenharmony_ci@Component({ freezeWhenInactive: true }) 131e41f4b71Sopenharmony_cistruct FreezeChild { 132e41f4b71Sopenharmony_ci @Link @Watch("onMessageUpdated") message: number 133e41f4b71Sopenharmony_ci private index: number = 0 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci onMessageUpdated() { 136e41f4b71Sopenharmony_ci console.info(`FreezeChild message callback func ${this.message}, index: ${this.index}`) 137e41f4b71Sopenharmony_ci } 138e41f4b71Sopenharmony_ci 139e41f4b71Sopenharmony_ci build() { 140e41f4b71Sopenharmony_ci Text("message" + `${this.message}, index: ${this.index}`) 141e41f4b71Sopenharmony_ci .fontSize(50) 142e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 143e41f4b71Sopenharmony_ci } 144e41f4b71Sopenharmony_ci} 145e41f4b71Sopenharmony_ci``` 146e41f4b71Sopenharmony_ci 147e41f4b71Sopenharmony_ciIn the preceding example: 148e41f4b71Sopenharmony_ci 149e41f4b71Sopenharmony_ci1. When **change message** is clicked, the value of **message** changes, and the @Watch decorated **onMessageUpdated** method of the **TabContent** component being displayed is called. 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ci2. When you click **two** to switch to another **TabContent** component, it switches from inactive to active, and the corresponding @Watch decorated **onMessageUpdated** method is called. 152e41f4b71Sopenharmony_ci 153e41f4b71Sopenharmony_ci3. When **change message** is clicked again, the value of **message** changes, and only the @Watch decorated **onMessageUpdated** method of the **TabContent** component being displayed is called. 154e41f4b71Sopenharmony_ci 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci### LazyForEach 159e41f4b71Sopenharmony_ci 160e41f4b71Sopenharmony_ci- You can freeze custom components cached in **LazyForEach** so that they do not trigger UI re-rendering. 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci```ts 163e41f4b71Sopenharmony_ci// Basic implementation of IDataSource to handle data listener 164e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 165e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 166e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci public totalCount(): number { 169e41f4b71Sopenharmony_ci return 0; 170e41f4b71Sopenharmony_ci } 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci public getData(index: number): string { 173e41f4b71Sopenharmony_ci return this.originDataArray[index]; 174e41f4b71Sopenharmony_ci } 175e41f4b71Sopenharmony_ci 176e41f4b71Sopenharmony_ci // This method is called by the framework to add a listener to the LazyForEach data source. 177e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 178e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 179e41f4b71Sopenharmony_ci console.info('add listener'); 180e41f4b71Sopenharmony_ci this.listeners.push(listener); 181e41f4b71Sopenharmony_ci } 182e41f4b71Sopenharmony_ci } 183e41f4b71Sopenharmony_ci 184e41f4b71Sopenharmony_ci // This method is called by the framework to remove the listener from the LazyForEach data source. 185e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 186e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 187e41f4b71Sopenharmony_ci if (pos >= 0) { 188e41f4b71Sopenharmony_ci console.info('remove listener'); 189e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 190e41f4b71Sopenharmony_ci } 191e41f4b71Sopenharmony_ci } 192e41f4b71Sopenharmony_ci 193e41f4b71Sopenharmony_ci // Notify LazyForEach that all child components need to be reloaded. 194e41f4b71Sopenharmony_ci notifyDataReload(): void { 195e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 196e41f4b71Sopenharmony_ci listener.onDataReloaded(); 197e41f4b71Sopenharmony_ci }) 198e41f4b71Sopenharmony_ci } 199e41f4b71Sopenharmony_ci 200e41f4b71Sopenharmony_ci // Notify LazyForEach that a child component needs to be added for the data item with the specified index. 201e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 202e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 203e41f4b71Sopenharmony_ci listener.onDataAdd(index); 204e41f4b71Sopenharmony_ci }) 205e41f4b71Sopenharmony_ci } 206e41f4b71Sopenharmony_ci 207e41f4b71Sopenharmony_ci // Notify LazyForEach that the data item with the specified index has changed and the child component needs to be rebuilt. 208e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 209e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 210e41f4b71Sopenharmony_ci listener.onDataChange(index); 211e41f4b71Sopenharmony_ci }) 212e41f4b71Sopenharmony_ci } 213e41f4b71Sopenharmony_ci 214e41f4b71Sopenharmony_ci // Notify LazyForEach that the child component that matches the specified index needs to be deleted. 215e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 216e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 217e41f4b71Sopenharmony_ci listener.onDataDelete(index); 218e41f4b71Sopenharmony_ci }) 219e41f4b71Sopenharmony_ci } 220e41f4b71Sopenharmony_ci} 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 223e41f4b71Sopenharmony_ci private dataArray: string[] = []; 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci public totalCount(): number { 226e41f4b71Sopenharmony_ci return this.dataArray.length; 227e41f4b71Sopenharmony_ci } 228e41f4b71Sopenharmony_ci 229e41f4b71Sopenharmony_ci public getData(index: number): string { 230e41f4b71Sopenharmony_ci return this.dataArray[index]; 231e41f4b71Sopenharmony_ci } 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 234e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 235e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 236e41f4b71Sopenharmony_ci } 237e41f4b71Sopenharmony_ci 238e41f4b71Sopenharmony_ci public pushData(data: string): void { 239e41f4b71Sopenharmony_ci this.dataArray.push(data); 240e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 241e41f4b71Sopenharmony_ci } 242e41f4b71Sopenharmony_ci} 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci@Entry 245e41f4b71Sopenharmony_ci@Component 246e41f4b71Sopenharmony_cistruct LforEachTest { 247e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 248e41f4b71Sopenharmony_ci @State @Watch("onMessageUpdated") message: number = 0; 249e41f4b71Sopenharmony_ci 250e41f4b71Sopenharmony_ci onMessageUpdated() { 251e41f4b71Sopenharmony_ci console.info(`LazyforEach message callback func ${this.message}`) 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci aboutToAppear() { 255e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 256e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 257e41f4b71Sopenharmony_ci } 258e41f4b71Sopenharmony_ci } 259e41f4b71Sopenharmony_ci 260e41f4b71Sopenharmony_ci build() { 261e41f4b71Sopenharmony_ci Column() { 262e41f4b71Sopenharmony_ci Button('change message').onClick(() => { 263e41f4b71Sopenharmony_ci this.message++ 264e41f4b71Sopenharmony_ci }) 265e41f4b71Sopenharmony_ci List({ space: 3 }) { 266e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 267e41f4b71Sopenharmony_ci ListItem() { 268e41f4b71Sopenharmony_ci FreezeChild({ message: this.message, index: item }) 269e41f4b71Sopenharmony_ci } 270e41f4b71Sopenharmony_ci }, (item: string) => item) 271e41f4b71Sopenharmony_ci }.cachedCount(5).height(500) 272e41f4b71Sopenharmony_ci } 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci } 275e41f4b71Sopenharmony_ci} 276e41f4b71Sopenharmony_ci 277e41f4b71Sopenharmony_ci@Component({ freezeWhenInactive: true }) 278e41f4b71Sopenharmony_cistruct FreezeChild { 279e41f4b71Sopenharmony_ci @Link @Watch("onMessageUpdated") message: number; 280e41f4b71Sopenharmony_ci private index: string = ""; 281e41f4b71Sopenharmony_ci 282e41f4b71Sopenharmony_ci aboutToAppear() { 283e41f4b71Sopenharmony_ci console.info(`FreezeChild aboutToAppear index: ${this.index}`) 284e41f4b71Sopenharmony_ci } 285e41f4b71Sopenharmony_ci 286e41f4b71Sopenharmony_ci onMessageUpdated() { 287e41f4b71Sopenharmony_ci console.info(`FreezeChild message callback func ${this.message}, index: ${this.index}`) 288e41f4b71Sopenharmony_ci } 289e41f4b71Sopenharmony_ci 290e41f4b71Sopenharmony_ci build() { 291e41f4b71Sopenharmony_ci Text("message" + `${this.message}, index: ${this.index}`) 292e41f4b71Sopenharmony_ci .width('90%') 293e41f4b71Sopenharmony_ci .height(160) 294e41f4b71Sopenharmony_ci .backgroundColor(0xAFEEEE) 295e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 296e41f4b71Sopenharmony_ci .fontSize(30) 297e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 298e41f4b71Sopenharmony_ci } 299e41f4b71Sopenharmony_ci} 300e41f4b71Sopenharmony_ci``` 301e41f4b71Sopenharmony_ci 302e41f4b71Sopenharmony_ciIn the preceding example: 303e41f4b71Sopenharmony_ci 304e41f4b71Sopenharmony_ci1. When **change message** is clicked, the value of **message** changes, the @Watch decorated **onMessageUpdated** method of the list items being displayed is called, and that of the cached list items is not called. (If the component is not frozen, the @Watch decorated **onMessageUpdated** method of both list items that are being displayed and cached list items is called.) 305e41f4b71Sopenharmony_ci 306e41f4b71Sopenharmony_ci2. When a list item moves from outside the list content area into the list content area, it switches from inactive to active, and the corresponding @Watch decorated **onMessageUpdated** method is called. 307e41f4b71Sopenharmony_ci 308e41f4b71Sopenharmony_ci3. When **change message** is clicked again, the value of **message** changes, and only the @Watch decorated **onMessageUpdated** method of the list items being displayed is called. 309e41f4b71Sopenharmony_ci 310e41f4b71Sopenharmony_ci 311e41f4b71Sopenharmony_ci 312e41f4b71Sopenharmony_ci### Navigation 313e41f4b71Sopenharmony_ci 314e41f4b71Sopenharmony_ci- When the navigation destination page is invisible, its child custom components are set to the inactive state and will not be re-rendered. When return to this page, its child custom components are restored to the active state and the @Watch callback is triggered to re-render the page. 315e41f4b71Sopenharmony_ci 316e41f4b71Sopenharmony_ci- In the following example, **NavigationContentMsgStack** is set to the inactive state, which does not respond to the change of the state variables, and does not trigger component re-rendering. 317e41f4b71Sopenharmony_ci 318e41f4b71Sopenharmony_ci```ts 319e41f4b71Sopenharmony_ci@Entry 320e41f4b71Sopenharmony_ci@Component 321e41f4b71Sopenharmony_cistruct MyNavigationTestStack { 322e41f4b71Sopenharmony_ci @Provide('pageInfo') pageInfo: NavPathStack = new NavPathStack(); 323e41f4b71Sopenharmony_ci @State @Watch("info") message: number = 0; 324e41f4b71Sopenharmony_ci @State logNumber: number = 0; 325e41f4b71Sopenharmony_ci 326e41f4b71Sopenharmony_ci info() { 327e41f4b71Sopenharmony_ci console.info(`freeze-test MyNavigation message callback ${this.message}`); 328e41f4b71Sopenharmony_ci } 329e41f4b71Sopenharmony_ci 330e41f4b71Sopenharmony_ci @Builder 331e41f4b71Sopenharmony_ci PageMap(name: string) { 332e41f4b71Sopenharmony_ci if (name === 'pageOne') { 333e41f4b71Sopenharmony_ci pageOneStack({ message: this.message, logNumber: this.logNumber }) 334e41f4b71Sopenharmony_ci } else if (name === 'pageTwo') { 335e41f4b71Sopenharmony_ci pageTwoStack({ message: this.message, logNumber: this.logNumber }) 336e41f4b71Sopenharmony_ci } else if (name === 'pageThree') { 337e41f4b71Sopenharmony_ci pageThreeStack({ message: this.message, logNumber: this.logNumber }) 338e41f4b71Sopenharmony_ci } 339e41f4b71Sopenharmony_ci } 340e41f4b71Sopenharmony_ci 341e41f4b71Sopenharmony_ci build() { 342e41f4b71Sopenharmony_ci Column() { 343e41f4b71Sopenharmony_ci Button('change message') 344e41f4b71Sopenharmony_ci .onClick(() => { 345e41f4b71Sopenharmony_ci this.message++; 346e41f4b71Sopenharmony_ci }) 347e41f4b71Sopenharmony_ci Navigation(this.pageInfo) { 348e41f4b71Sopenharmony_ci Column() { 349e41f4b71Sopenharmony_ci Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) 350e41f4b71Sopenharmony_ci .width('80%') 351e41f4b71Sopenharmony_ci .height(40) 352e41f4b71Sopenharmony_ci .margin(20) 353e41f4b71Sopenharmony_ci .onClick(() => { 354e41f4b71Sopenharmony_ci this.pageInfo.pushPath({ name: 'pageOne' }); // Push the navigation destination page specified by name to the navigation stack. 355e41f4b71Sopenharmony_ci }) 356e41f4b71Sopenharmony_ci } 357e41f4b71Sopenharmony_ci }.title('NavIndex') 358e41f4b71Sopenharmony_ci .navDestination(this.PageMap) 359e41f4b71Sopenharmony_ci .mode(NavigationMode.Stack) 360e41f4b71Sopenharmony_ci } 361e41f4b71Sopenharmony_ci } 362e41f4b71Sopenharmony_ci} 363e41f4b71Sopenharmony_ci 364e41f4b71Sopenharmony_ci@Component 365e41f4b71Sopenharmony_cistruct pageOneStack { 366e41f4b71Sopenharmony_ci @Consume('pageInfo') pageInfo: NavPathStack; 367e41f4b71Sopenharmony_ci @State index: number = 1; 368e41f4b71Sopenharmony_ci @Link message: number; 369e41f4b71Sopenharmony_ci @Link logNumber: number; 370e41f4b71Sopenharmony_ci 371e41f4b71Sopenharmony_ci build() { 372e41f4b71Sopenharmony_ci NavDestination() { 373e41f4b71Sopenharmony_ci Column() { 374e41f4b71Sopenharmony_ci NavigationContentMsgStack({ message: this.message, index: this.index, logNumber: this.logNumber }) 375e41f4b71Sopenharmony_ci Text("cur stack size:" + `${this.pageInfo.size()}`) 376e41f4b71Sopenharmony_ci .fontSize(30) 377e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 378e41f4b71Sopenharmony_ci Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) 379e41f4b71Sopenharmony_ci .width('80%') 380e41f4b71Sopenharmony_ci .height(40) 381e41f4b71Sopenharmony_ci .margin(20) 382e41f4b71Sopenharmony_ci .onClick(() => { 383e41f4b71Sopenharmony_ci this.pageInfo.pushPathByName('pageTwo', null); 384e41f4b71Sopenharmony_ci }) 385e41f4b71Sopenharmony_ci Button('Back Page', { stateEffect: true, type: ButtonType.Capsule }) 386e41f4b71Sopenharmony_ci .width('80%') 387e41f4b71Sopenharmony_ci .height(40) 388e41f4b71Sopenharmony_ci .margin(20) 389e41f4b71Sopenharmony_ci .onClick(() => { 390e41f4b71Sopenharmony_ci this.pageInfo.pop(); 391e41f4b71Sopenharmony_ci }) 392e41f4b71Sopenharmony_ci }.width('100%').height('100%') 393e41f4b71Sopenharmony_ci }.title('pageOne') 394e41f4b71Sopenharmony_ci .onBackPressed(() => { 395e41f4b71Sopenharmony_ci this.pageInfo.pop(); 396e41f4b71Sopenharmony_ci return true; 397e41f4b71Sopenharmony_ci }) 398e41f4b71Sopenharmony_ci } 399e41f4b71Sopenharmony_ci} 400e41f4b71Sopenharmony_ci 401e41f4b71Sopenharmony_ci@Component 402e41f4b71Sopenharmony_cistruct pageTwoStack { 403e41f4b71Sopenharmony_ci @Consume('pageInfo') pageInfo: NavPathStack; 404e41f4b71Sopenharmony_ci @State index: number = 2; 405e41f4b71Sopenharmony_ci @Link message: number; 406e41f4b71Sopenharmony_ci @Link logNumber: number; 407e41f4b71Sopenharmony_ci 408e41f4b71Sopenharmony_ci build() { 409e41f4b71Sopenharmony_ci NavDestination() { 410e41f4b71Sopenharmony_ci Column() { 411e41f4b71Sopenharmony_ci NavigationContentMsgStack({ message: this.message, index: this.index, logNumber: this.logNumber }) 412e41f4b71Sopenharmony_ci Text("cur stack size:" + `${this.pageInfo.size()}`) 413e41f4b71Sopenharmony_ci .fontSize(30) 414e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 415e41f4b71Sopenharmony_ci Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) 416e41f4b71Sopenharmony_ci .width('80%') 417e41f4b71Sopenharmony_ci .height(40) 418e41f4b71Sopenharmony_ci .margin(20) 419e41f4b71Sopenharmony_ci .onClick(() => { 420e41f4b71Sopenharmony_ci this.pageInfo.pushPathByName('pageThree', null); 421e41f4b71Sopenharmony_ci }) 422e41f4b71Sopenharmony_ci Button('Back Page', { stateEffect: true, type: ButtonType.Capsule }) 423e41f4b71Sopenharmony_ci .width('80%') 424e41f4b71Sopenharmony_ci .height(40) 425e41f4b71Sopenharmony_ci .margin(20) 426e41f4b71Sopenharmony_ci .onClick(() => { 427e41f4b71Sopenharmony_ci this.pageInfo.pop(); 428e41f4b71Sopenharmony_ci }) 429e41f4b71Sopenharmony_ci }.width('100%').height('100%') 430e41f4b71Sopenharmony_ci }.title('pageTwo') 431e41f4b71Sopenharmony_ci .onBackPressed(() => { 432e41f4b71Sopenharmony_ci this.pageInfo.pop(); 433e41f4b71Sopenharmony_ci return true; 434e41f4b71Sopenharmony_ci }) 435e41f4b71Sopenharmony_ci } 436e41f4b71Sopenharmony_ci} 437e41f4b71Sopenharmony_ci 438e41f4b71Sopenharmony_ci@Component 439e41f4b71Sopenharmony_cistruct pageThreeStack { 440e41f4b71Sopenharmony_ci @Consume('pageInfo') pageInfo: NavPathStack; 441e41f4b71Sopenharmony_ci @State index: number = 3; 442e41f4b71Sopenharmony_ci @Link message: number; 443e41f4b71Sopenharmony_ci @Link logNumber: number; 444e41f4b71Sopenharmony_ci 445e41f4b71Sopenharmony_ci build() { 446e41f4b71Sopenharmony_ci NavDestination() { 447e41f4b71Sopenharmony_ci Column() { 448e41f4b71Sopenharmony_ci NavigationContentMsgStack({ message: this.message, index: this.index, logNumber: this.logNumber }) 449e41f4b71Sopenharmony_ci Text("cur stack size:" + `${this.pageInfo.size()}`) 450e41f4b71Sopenharmony_ci .fontSize(30) 451e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 452e41f4b71Sopenharmony_ci Button('Next Page', { stateEffect: true, type: ButtonType.Capsule }) 453e41f4b71Sopenharmony_ci .width('80%') 454e41f4b71Sopenharmony_ci .height(40) 455e41f4b71Sopenharmony_ci .margin(20) 456e41f4b71Sopenharmony_ci .onClick(() => { 457e41f4b71Sopenharmony_ci this.pageInfo.pushPathByName('pageOne', null); 458e41f4b71Sopenharmony_ci }) 459e41f4b71Sopenharmony_ci Button('Back Page', { stateEffect: true, type: ButtonType.Capsule }) 460e41f4b71Sopenharmony_ci .width('80%') 461e41f4b71Sopenharmony_ci .height(40) 462e41f4b71Sopenharmony_ci .margin(20) 463e41f4b71Sopenharmony_ci .onClick(() => { 464e41f4b71Sopenharmony_ci this.pageInfo.pop(); 465e41f4b71Sopenharmony_ci }) 466e41f4b71Sopenharmony_ci }.width('100%').height('100%') 467e41f4b71Sopenharmony_ci }.title('pageThree') 468e41f4b71Sopenharmony_ci .onBackPressed(() => { 469e41f4b71Sopenharmony_ci this.pageInfo.pop(); 470e41f4b71Sopenharmony_ci return true; 471e41f4b71Sopenharmony_ci }) 472e41f4b71Sopenharmony_ci } 473e41f4b71Sopenharmony_ci} 474e41f4b71Sopenharmony_ci 475e41f4b71Sopenharmony_ci@Component({ freezeWhenInactive: true }) 476e41f4b71Sopenharmony_cistruct NavigationContentMsgStack { 477e41f4b71Sopenharmony_ci @Link @Watch("info") message: number; 478e41f4b71Sopenharmony_ci @Link index: number; 479e41f4b71Sopenharmony_ci @Link logNumber: number; 480e41f4b71Sopenharmony_ci 481e41f4b71Sopenharmony_ci info() { 482e41f4b71Sopenharmony_ci console.info(`freeze-test NavigationContent message callback ${this.message}`); 483e41f4b71Sopenharmony_ci console.info(`freeze-test ---- called by content ${this.index}`); 484e41f4b71Sopenharmony_ci this.logNumber++; 485e41f4b71Sopenharmony_ci } 486e41f4b71Sopenharmony_ci 487e41f4b71Sopenharmony_ci build() { 488e41f4b71Sopenharmony_ci Column() { 489e41f4b71Sopenharmony_ci Text("msg:" + `${this.message}`) 490e41f4b71Sopenharmony_ci .fontSize(30) 491e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 492e41f4b71Sopenharmony_ci Text("log number:" + `${this.logNumber}`) 493e41f4b71Sopenharmony_ci .fontSize(30) 494e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 495e41f4b71Sopenharmony_ci } 496e41f4b71Sopenharmony_ci } 497e41f4b71Sopenharmony_ci} 498e41f4b71Sopenharmony_ci``` 499e41f4b71Sopenharmony_ci 500e41f4b71Sopenharmony_ciIn the preceding example: 501e41f4b71Sopenharmony_ci 502e41f4b71Sopenharmony_ci1. When **change message** is clicked, the value of **message** changes, and the @Watch decorated **info** method of the **MyNavigationTestStack** component being displayed is called. 503e41f4b71Sopenharmony_ci 504e41f4b71Sopenharmony_ci2. When **Next Page** is clicked, **PageOne** is displayed, and the **PageOneStack** node is created. 505e41f4b71Sopenharmony_ci 506e41f4b71Sopenharmony_ci3. When **change message** is clicked again, the value of **message** changes, and only the @Watch decorated **info** method of the **NavigationContentMsgStack** child component in **pageOneStack** is called. 507e41f4b71Sopenharmony_ci 508e41f4b71Sopenharmony_ci4. When **Next Page** is clicked again, **PageTwo** is displayed, and the **pageTwoStack** node is created. 509e41f4b71Sopenharmony_ci 510e41f4b71Sopenharmony_ci5. When **change message** is clicked again, the value of **message** changes, and only the @Watch decorated **info** method of the **NavigationContentMsgStack** child component in **pageTwoStack** is called. 511e41f4b71Sopenharmony_ci 512e41f4b71Sopenharmony_ci6. When **Next Page** is clicked again, **PageThree** is displayed, and the **pageThreeStack** node is created. 513e41f4b71Sopenharmony_ci 514e41f4b71Sopenharmony_ci7. When **change message** is clicked again, the value of **message** changes, and only the @Watch decorated **info** method of the **NavigationContentMsgStack** child component in **pageThreeStack** is called. 515e41f4b71Sopenharmony_ci 516e41f4b71Sopenharmony_ci8. When **Back Page** is clicked, **PageTwo** is displayed, and only the @Watch decorated **info** method of the **NavigationContentMsgStack** child component in **pageTwoStack** is called. 517e41f4b71Sopenharmony_ci 518e41f4b71Sopenharmony_ci9. When **Back Page** is clicked again, **PageOne** is displayed, and only the @Watch decorated **info** method of the **NavigationContentMsgStack** child component in **PageOne** is called. 519e41f4b71Sopenharmony_ci 520e41f4b71Sopenharmony_ci10. When **Back Page** is clicked again, the initial page is displayed, and no method is called. 521e41f4b71Sopenharmony_ci 522e41f4b71Sopenharmony_ci 523