系列:HarmonyOS 开发入门 · 05
HarmonyOS 生命周期最容易踩坑的地方,不是回调太多,而是不同层级的生命周期名字很像。
组件有组件生命周期,页面有页面生命周期;换成 Navigation 后,NavDestination 又有自己的一套页面生命周期。
如果全部当成"页面出现了"来用,接口请求很容易重复触发。
1. 先分清:组件生命周期和页面生命周期
普通 ArkUI 自定义组件常见:
ts
aboutToAppear()
aboutToDisappear()
页面入口组件还可以关注:
ts
onPageShow()
onPageHide()
onBackPress()
两组不是一回事。
2. aboutToAppear 什么时候触发
aboutToAppear 是组件级生命周期。
自定义组件实例创建后、build() 执行前会触发。
ts
@Component
struct UserCard {
aboutToAppear() {
console.info('UserCard aboutToAppear')
}
build() {
Text('User')
}
}
它适合做与"组件创建"绑定的轻量初始化。
但如果这个组件在列表里出现 100 次,那它也可能创建很多次。所以不要看到 aboutToAppear 就塞网络请求。
3. onPageShow 才是页面显示语义
对于 @Entry 页面:
ts
onPageShow() {
console.info('page show')
}
onPageHide() {
console.info('page hide')
}
页面从其他页面返回、应用从后台回到前台等场景,都可能触发 onPageShow。
因此它更适合:
- 页面每次重新可见时刷新;
- 回到前台后重新检查状态;
- 刷新可能被其他页面修改的数据。
但它不等于"只执行一次"。
4. 首次进入时大概发生什么
一个简单页面首次创建时,可以理解成:
text
aboutToAppear
↓
build
↓
页面展示
↓
onPageShow
如果还有子组件,子组件也会走自己的创建生命周期。
所以把初始化同时写在 aboutToAppear 和 onPageShow,非常容易执行两遍。
5. 页面切到后台
应用进入后台时,当前页面通常会收到隐藏相关回调,但组件本身未必被销毁。
这点很重要:
"看不见"不等于"被销毁"。
因此资源释放要区分:
- 页面暂时不可见;
- 组件真正销毁。
比如暂停一个页面动画,可以放在页面隐藏时;注销只属于组件实例的监听,则更适合在销毁时处理。
6. aboutToDisappear 不适合再改状态
组件即将销毁时,做清理是合理的:
ts
aboutToDisappear() {
// 注销监听、释放当前组件资源
}
但不要在这里继续修改会触发 UI 更新的状态变量。
组件都准备离开组件树了,再发起一轮状态刷新通常没有意义,还可能引发不稳定行为。
7. 一个常见错误:接口请求两次
假设你写了:
ts
aboutToAppear() {
this.loadData()
}
onPageShow() {
this.loadData()
}
首屏就可能请求两次。
更合理的方式是先明确业务:
只在首次创建加载
放在组件创建语义中,并确保组件不会频繁被重新创建。
每次返回页面都刷新
使用页面展示语义。
首次加载一次,后续按条件刷新
增加状态控制:
ts
@State hasLoaded: boolean = false
onPageShow() {
if (!this.hasLoaded) {
this.hasLoaded = true
this.loadData()
return
}
this.refreshIfNeeded()
}
8. 使用 Navigation 后怎么办
现在新项目更推荐使用 Navigation + NavPathStack。
这时页面通常以 NavDestination 为核心,页面显示、隐藏、销毁会有更明确的 Navigation 生命周期事件。
所以如果项目已经全面使用 Navigation,不建议继续拿旧的页面路由思路硬套。
我后面会单独用一篇文章讲 NavDestination 生命周期。
9. 我的实际建议
写生命周期代码前先问三个问题:
- 这是"组件创建"还是"页面重新可见"?
- 这段逻辑需要执行一次还是每次都执行?
- 页面隐藏时只是暂停,还是要真正释放?
这三个问题想清楚,生命周期代码基本不会乱。
总结
最容易记的一句话:
aboutToAppear关注组件创建,onPageShow关注页面再次可见。
下一篇再往上一层,聊 UIAbility 生命周期。它和页面生命周期不是替代关系,而是应用组件层级更高的一套机制。