TabContent预加载问题
===============

#### 问题现象

在aboutToAppear回调中使用preloadItems方法来实现TabContent组件的预加载，结果未生效，为什么？如何解决？

#### 背景知识

*   [aboutToAppear](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-custom-component-lifecycle#abouttoappear)函数在创建自定义组件的新实例后，在执行其build()函数之前执行，早于[Tabs](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs)组件的渲染。
*   [preloadItems](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs#preloaditems12)是控制器[TabsController](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs#tabscontroller)的一个方法，能够控制Tabs预加载指定子节点。调用该接口后会一次性加载所有指定的子节点，预加载到不存在的索引时就会报错。
*   Router路由与导航Navigation各自的生命周期不同，具体情况如下图：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/5f/v3/kBuBkw9bTdCm6ziTs8Iq1A/zh-cn_image_0000002658928745.png?HW-CC-KV=V1&HW-CC-Date=20260709T134033Z&HW-CC-Expire=86400&HW-CC-Sign=DED0EE6FF5445BFFD37D83AFC5524DF0F7EB7EF25E69705DC5D812DD9E269AD9 "点击放大") ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/aa/v3/Zs-NAF35T5aKPqgNKn5y2A/zh-cn_image_0000002658808797.png?HW-CC-KV=V1&HW-CC-Date=20260709T134033Z&HW-CC-Expire=86400&HW-CC-Sign=830D986A99EA954C76212D4D7DB3F5B70277CF849F5A36D9DE2A526A68DA8D21 "点击放大")
    

#### 问题定位

在Tabs组件中，将预加载方法preloadItems在aboutToAppear方法中直接调用，由于aboutToAppear会在Tabs组件完成渲染前就被调用，Tabs组件的索引也就获取不到，因此导致preloadItems方法预加载了不存在的索引，从而预加载失败并且产生报错。

#### 分析结论

预加载方法preloadItems在aboutToAppear回调中被直接调用，导致预加载了不存在的索引，从而致使预加载失败。

#### 修改建议

aboutToAppear被调用的时候Tabs组件尚未完成渲染，导致Tabs的预加载方法加载不存在的索引，从而预加载失败，使用执行时间相对靠后的**生命周期**执行预加载方法即可预防问题，方案如下：

*   **场景一**：使用Router页面生命周期函数[onPageShow](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-custom-component-lifecycle#onpageshow)。
    
    onPageShow回调在Router页面每次显示时都会触发一次，可以在该生命周期中调用预加载方法preloadItems，通过打印日志的方法来判断TabContent预加载是否成功，调用onPageShow的示例代码如下：
    
    import { BusinessError } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct RouterPageShowSolution {
      tabsController: TabsController \= new TabsController();
      tabsData: number\[\] \= \[1, 2, 3, 4, 5\];
    
      onPageShow(): void {
        this.tabsController.preloadItems(\[0, 1, 2, 3\]).then(() \=\> {
          console.info('onPageShow preloadItems success.');
        })
          .catch((error: BusinessError) \=\> {
            console.error(\`Failed to publish notification, error：${error}\`);
          });
      }
    
      build() {
        Column() {
          Tabs({ controller: this.tabsController }) {
            ForEach(this.tabsData, (item: number) \=\> {
              TabContent() {
                Text(item.toString());
              };
            });
          };
        }.height('100%').width('100%');
      }
    }
    
*   **场景二**：使用组件挂载事件[onAppear](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-events-show-hide#onappear)。
    
    onAppear回调在组件挂载显示后触发，可以在该生命周期中调用预加载方法preloadItems，通过打印日志的方法来判断TabContent预加载是否成功，调用onAppear的示例代码如下：
    
    import { BusinessError } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct NavAppearSolution {
      pathStack: NavPathStack \= new NavPathStack();
      tabsController: TabsController \= new TabsController();
      tabsData: number\[\] \= \[1, 2, 3, 4, 5\];
    
      build() {
        Navigation(this.pathStack) {
          Tabs({ controller: this.tabsController }) {
            ForEach(this.tabsData, (item: number) \=\> {
              TabContent() {
                Text(item.toString());
              };
            });
          };
        }.height('100%').width('100%')
        .onAppear(() \=\> {
          this.tabsController.preloadItems(\[0, 1, 2, 3\])
            .then(() \=\> {
              console.info('onAppear preloadItems success.');
            })
            .catch((error: BusinessError) \=\> {
              console.error(\`Failed to publish notification, error：${error}\`);
            });
        });
      }
    }
    

#### 常见FAQ

Q：Tabs组件预加载生效之后会调用aboutToAppear方法吗？

A：被预加载的TabContent中的对应控件的aboutToAppear方法会被调用，可以添加日志来验证。

Q：有没有办法能够在aboutToAppear回调里进行预加载？

A：确认TabContent创建完成后再进行Tabs组件的预加载，可以通过同步获取数据再进行预加载。

Q：为什么页面组件在TabContent加载的时候只调用aboutToAppear，不调用onPageShow？

A：onPageShow是页面级的生命周期，Tabs切换触发的应该是子组件组件级的生命周期aboutToAppear。

#### 总结

由于aboutToAppear回调会在执行其build()函数之前执行，此时preloadItems方法让未完成渲染的Tabs组件去预加载子组件会失败，本文主要提供了两种方案，onPageShow回调和onAppear回调都能够在Tabs渲染完成之后调用。