HarmonyOS ArkUI 列表刷新为什么会闪:加载态、空态、错误态和旧数据怎么分开
HarmonyOS ArkUI 列表刷新为什么会闪加载态、空态、错误态和旧数据怎么分开先把问题说清楚列表刷新时最常见的问题是用户刚输入关键词列表马上清空然后加载一结束又显示新结果。网速慢一点时页面会在“旧数据、加载中、空状态”之间来回跳。这个问题表面上看是 UI 小毛病实际上多半是状态边界没有拆清楚。页面里同时有“正在加载”“已有旧数据”“新请求结果”“空状态”“错误状态”如果全部塞进一个布尔值里后面一定会乱。这篇只讲一个可复现问题列表刷新闪烁。我会先写一个容易出错的版本再写一个更稳的版本最后给出检查方法。环境和验证目标项说明技术方向HarmonyOS / ArkUI / ArkTS页面模型Stage 模型页面关注点列表刷新闪烁验证目标操作顺序变化时页面状态仍然可预测适用场景搜索页、筛选页、列表页、详情页返回刷新错误写法只用一个状态硬撑先看一个很常见的写法。代码短但后面排查很难。Entry Component struct BadCasePage { State loading: boolean false; State keyword: string ; State list: string[] []; State errorText: string ; private async reload() { this.loading true; this.errorText ; try { const result await this.mockRequest(this.keyword); this.list result; } catch (err) { this.errorText 加载失败; this.list []; } this.loading false; } private async mockRequest(keyword: string): Promisestring[] { return new Promise((resolve) { setTimeout(() resolve(keyword ? [keyword 结果] : []), 600); }); } build() { Column({ space: 12 }) { Search({ value: this.keyword, placeholder: 输入关键词 }) .onChange((value: string) { this.keyword value; this.reload(); }) if (this.loading) { Text(加载中) } else if (this.errorText.length 0) { Text(this.errorText) } else if (this.list.length 0) { Text(没有结果) } else { ForEach(this.list, (item: string) { Text(item).fontSize(16) }, (item: string) item) } } .padding(16) } }这段代码能跑但它有几个隐患- 请求慢一点时旧请求可能覆盖新请求- 空状态和加载状态挤在一起页面会闪- 错误后再搜索旧错误文案可能残留- 列表清空太早用户会看到内容突然消失。稳一点的拆法把页面状态拆成模型我的做法是把页面状态拆成明确的模型。不要让 loading、error、list 到处散着改。type PagePhase idle | loading | success | empty | error; class PageStateT { phase: PagePhase idle; data: T[] []; errorText: string ; requestVersion: number 0; startRequest(): number { this.phase loading; this.errorText ; this.requestVersion 1; return this.requestVersion; } applySuccess(version: number, data: T[]) { if (version ! this.requestVersion) { return; } this.data data; this.phase data.length 0 ? success : empty; } applyError(version: number, message: string) { if (version ! this.requestVersion) { return; } this.errorText message; this.phase error; } }这里的关键是 coderequestVersion/code。每次请求开始都拿一个版本号返回时只允许最新版本写回页面。这样输入很快时旧请求就不会覆盖新结果。把模型放回 ArkUI 页面Observed class RecipeSearchState extends PageStatestring {} Entry Component struct BetterCasePage { State keyword: string ; State state: RecipeSearchState new RecipeSearchState(); private async reload() { const version this.state.startRequest(); try { const result await this.mockRequest(this.keyword); this.state.applySuccess(version, result); } catch (err) { this.state.applyError(version, 加载失败请稍后再试); } } private async mockRequest(keyword: string): Promisestring[] { return new Promise((resolve) { setTimeout(() resolve(keyword ? [keyword 结果] : []), 600); }); } Builder buildContent() { if (this.state.phase loading) { LoadingProgress() } else if (this.state.phase error) { Text(this.state.errorText).fontColor(#C0372B) } else if (this.state.phase empty) { Text(没有匹配结果可以换个关键词) } else { ForEach(this.state.data, (item: string) { Text(item).fontSize(16).padding(12) }, (item: string) item) } } build() { Column({ space: 12 }) { Search({ value: this.keyword, placeholder: 输入关键词 }) .onChange((value: string) { this.keyword value; this.reload(); }) this.buildContent() } .padding(16) } }这种写法比一个 loading 变量长一点但排查问题更直接。页面到底是加载中、空结果、成功还是失败看 codephase/code 就够了。案例二旧数据要不要保留如果是下拉刷新我会保留旧数据只在顶部显示刷新状态如果是换关键词搜索我会进入 loading 或 skeleton。两种场景不要混用否则用户会以为当前列表就是新条件的结果。class QueryGuard { private currentVersion: number 0; next(): number { this.currentVersion 1; return this.currentVersion; } isLatest(version: number): boolean { return version this.currentVersion; } } Component struct GuardUsagePage { State guard: QueryGuard new QueryGuard(); State text: string ; private async runTask(keyword: string) { const version this.guard.next(); const result await this.remoteSearch(keyword); if (!this.guard.isLatest(version)) { return; } this.text result; } private async remoteSearch(keyword: string): Promisestring { return new Promise((resolve) { setTimeout(() resolve(结果 keyword), 300); }); } }这个小封装适合放到搜索、筛选、分页加载这些位置。只要有“后发请求应该覆盖先发请求”的场景就可以用。怎么验证没有写虚我会按这几步测1. 连续快速输入三个关键词看最后显示的是不是最后一个关键词的结果。2. 输入不存在的关键词看页面是否进入 empty而不是一直 loading。3. 模拟请求失败看错误文案出现后再次搜索是否能恢复。4. 切换筛选条件后看分页和旧列表是否被正确重置。5. 重复进入页面确认没有旧错误、旧空状态残留。如果这几步都过说明这套状态边界是能经得起操作顺序变化的。我会怎么选方案简单页面可以直接用 loading、list、errorText 三个状态不必上来就封装模型。但只要页面出现搜索、防抖、筛选、分页、错误重试我就会把状态收进一个模型里。原因很简单页面越复杂越不能让状态到处散着改。后面如果要复用可以把 codePageState/code 和 codeQueryGuard/code 单独抽出来。不同页面只需要换数据类型和请求方法状态流转还是同一套。

相关新闻

小程序毕设选题推荐:基于 SpringBoot 的匿名投票管理系统的设计与实现 多场景在线投票评选服务小程序的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

小程序毕设选题推荐:基于 SpringBoot 的匿名投票管理系统的设计与实现 多场景在线投票评选服务小程序的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/7/21 0:59:50 阅读更多 →
从3D到VR:基于Unity的打飞碟游戏开发全流程与架构解析

从3D到VR:基于Unity的打飞碟游戏开发全流程与架构解析

1. 项目概述:从经典游戏到沉浸式体验的跨越如果你对游戏开发感兴趣,或者想踏入虚拟现实(VR)这个充满想象力的领域,那么“打飞碟”这个看似简单的游戏原型,绝对是一个绝佳的起点。它就像编程界的“Hello Wor…

2026/7/21 0:59:50 阅读更多 →
深度解析H5ANAG6NAMR-UHC:SK海力士16Gb DDR4高密度内存颗粒

深度解析H5ANAG6NAMR-UHC:SK海力士16Gb DDR4高密度内存颗粒

H5ANAG6NAMR-UHC:SK海力士16Gb DDR4 SDRAM颗粒深度解析在服务器、高性能计算平台、高端游戏笔记本以及人工智能加速设备等对内存密度和带宽有较高要求的应用领域,系统内存的选型直接影响着数据处理能力和整体性能表现。DDR4 SDRAM凭借其高数据速率和低电…

2026/7/21 0:59:50 阅读更多 →

最新新闻

ShaderGraph采样渐变节点:从原理到实战的完整指南

ShaderGraph采样渐变节点:从原理到实战的完整指南

1. 项目概述:为什么我们需要深入理解Sample Gradient Node?在ShaderGraph的世界里,节点是构建视觉效果的基石。当你第一次打开ShaderGraph,面对琳琅满目的节点库时,可能会感到一丝迷茫。其中,Sample Gradie…

2026/7/22 6:14:07 阅读更多 →
C++实战:基于OpenCV的多路视频实时融合系统开发指南

C++实战:基于OpenCV的多路视频实时融合系统开发指南

1. 项目概述:当视频不止一个画面如果你玩过一些大型的演出或者看过安防监控中心的大屏,可能会注意到一个现象:多个不同来源的视频画面,可以无缝地拼接在一起,形成一个更大的、连贯的视野。比如,一场演唱会的…

2026/7/22 6:14:07 阅读更多 →
奇迹MU剑与翼官方下载与高效挂机攻略

奇迹MU剑与翼官方下载与高效挂机攻略

1. 奇迹MU剑与翼官方下载全流程解析作为一款运营近20年的经典网游,《奇迹MU》剑与翼版本依然保持着旺盛的生命力。对于新老玩家而言,找到安全可靠的官方下载渠道是游戏体验的第一步。目前官方提供了三种主流下载方式:官网直链下载&#xff1a…

2026/7/22 6:14:07 阅读更多 →
深入解析GoogleTest断言机制:从基础使用到高级实践

深入解析GoogleTest断言机制:从基础使用到高级实践

1. 项目概述:为什么断言是单元测试的灵魂如果你写过单元测试,尤其是用过GoogleTest(gtest),那你一定对EXPECT_EQ、ASSERT_TRUE这类语句不陌生。它们就是断言,是测试用例里最核心的“检查点”。但很多人可能…

2026/7/22 6:14:07 阅读更多 →
2D游戏开发全流程解析:从引擎选择到性能优化实战

2D游戏开发全流程解析:从引擎选择到性能优化实战

这次来看一个名为《Deadman》的2D游戏项目,从标题标注的版本日期20260518来看,这应该是一个持续开发中的独立游戏作品。对于关注独立游戏开发、2D游戏设计或者想了解最新游戏项目动态的读者来说,这个项目值得关注。从项目标题的"日常2D&…

2026/7/22 6:14:07 阅读更多 →
计算机网络端口详解:从基础概念到安全实践

计算机网络端口详解:从基础概念到安全实践

1. 端口基础概念解析端口是计算机网络通信中的逻辑概念,它就像一栋大楼里的房间号,为不同服务提供了独立的通信通道。在TCP/IP协议栈中,端口号范围从0到65535,每个端口对应特定的服务或应用程序。端口主要分为三大类:公…

2026/7/22 6:13:07 阅读更多 →

日新闻

TI DSP系统配置模块SYSCFG详解:中断机制与主设备优先级配置实战

TI DSP系统配置模块SYSCFG详解:中断机制与主设备优先级配置实战

1. 项目概述与SYSCFG模块的核心价值在嵌入式系统,尤其是像TI C6000系列这样的高性能DSP开发中,我们常常会与芯片手册里那些密密麻麻的寄存器打交道。很多开发者可能更关注算法实现、内存优化或者外设驱动,但对于一个稳定、高效的系统而言&…

2026/7/22 0:00:26 阅读更多 →
微信Server酱:高到达率的应急通知方案实践

微信Server酱:高到达率的应急通知方案实践

1. 为什么我们需要"最次"的通知方案? 在数字化协作环境中,消息通知系统的重要性不言而喻明。但现实情况是,企业级通知方案往往需要复杂的API对接(如企业微信、钉钉、飞书),个人开发者的小项目又经…

2026/7/22 0:00:26 阅读更多 →
甲方要的“简洁“PPT,到底是简洁还是省事?

甲方要的“简洁“PPT,到底是简洁还是省事?

甲方说"简洁一点",乙方听到的是"少做几页"。甲方说"不要太复杂",乙方理解成"别放图表了"。结果交过去,甲方说"我说的简洁不是这个意思"。"简洁"这个词在PPT语境里,是…

2026/7/22 0:00:26 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 8:48:31 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 5:34:47 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 8:25:39 阅读更多 →

月新闻