onshow中刷新数据需精准控制:仅在必要时触发,避免重复请求、分页错乱和状态残留,注意平台差异与内存泄漏风险。

直接在 onShow 里拉数据是最稳妥的起点,但盲目搬移逻辑反而会引发重复请求、分页错乱或状态残留——关键不是“要不要刷”,而是“什么时候刷、刷什么、怎么避免副作用”。
onShow 中刷新数据:为什么它常被写错
很多人把 onLoad 的全部逻辑复制进 onShow,结果页面一显示就发两次请求(onLoad 一次 + onShow 一次),或者下拉刷新后返回,页码还是上次的 this.page = 2,导致新数据漏掉。
- 只在真正需要时才触发:首次进入已由
onLoad处理,onShow中应加判断,比如用this.dataLoaded标志位控制 - 重置分页/筛选状态:若页面支持搜索或分页,
onShow开头应显式设this.page = 1、this.searchKey = '' - 避免
loading冲突:多个onShow快速触发(如切后台再切回)可能并发请求,建议加this.loading锁或节流 - H5 环境下,iOS 微信 WebView 有时会延迟触发
onShow,不要依赖setTimeout补救,优先检查是否误用了navigationStyle: custom却没手动调uni.navigateBack()
事件总线(uni.$on/uni.$emit):必须配对卸载
当你需要“仅编辑后才刷新”,而不是每次返回都刷,事件总线是更精准的选择。但它极易因 onUnload 漏掉 uni.$off 导致内存泄漏和多次触发。
- 监听必须写在
onLoad或mounted,但卸载必须严格对应写在onUnload(不是onHide) - 传函数引用,别传匿名函数:
uni.$on('refreshList', this.handleRefresh),然后uni.$off('refreshList', this.handleRefresh) - 不要在
onShow里重复uni.$on,否则每次显示都新增监听器 - 真机调试时,若发现事件触发两次,大概率是上一页实例没被销毁(比如用了
redirect而非navigateBack),或onUnload根本没执行(页面栈异常)
eventChannel:适合跳转即通信的场景
如果你是从 A 页跳到 B 页(uni.navigateTo),且 B 页操作完要立刻通知 A 页刷新,eventChannel 比全局事件总线更轻量、更可控——它天然绑定跳转关系,不跨页面污染。
- A 页跳转时创建 channel:
uni.navigateTo({ url: '/pages/b/b', events: { refresh: () => this.getData() } }) - B 页只能在
onLoad中通过this.getOpenerEventChannel()获取 channel,并且必须在onLoad里调.on('refresh', );放到onShow就失效 -
eventChannel不支持 H5 端(H5 无 opener 概念),需降级为uni.setStorageSync+onShow轮询读取 - B 页返回前调用:
this.getOpenerEventChannel().emit('refresh')
getCurrentPages 直接改 data:高风险操作
有人用 getCurrentPages() 拿到上一页实例后直接修改其 data,比如 pages[pages.length - 2].data.list = [...]。这种写法看似快,但破坏响应式更新机制,Vue 实例未感知变化,视图不更新,且在 H5 和 App 端行为不一致。
- 优先用
this.setData()(小程序)或this.$set()/this.list = [](Vue 响应式赋值) - 复杂状态建议走 Pinia 或
vuex,避免跨页面强耦合 - 若真要用
getCurrentPages(),务必先if (page && page.$vm)判空,再调用其暴露的方法(如page.$vm.refresh()),而非直改data
最易被忽略的是:不同平台对 onShow 的触发时机差异极大,尤其 H5 在 iOS 微信中可能延迟几百毫秒;而 eventChannel 在 H5 下完全不可用——这意味着你写的“精准刷新”逻辑,在真机测试前根本看不出问题。











