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![TabContent.gif](figures/TabContent.gif)
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![FrezzeLazyforEach.gif](figures/FrezzeLazyforEach.gif)
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![navigation-freeze.gif](figures/navigation-freeze.gif)
523