第 16 天|网络四态:loading、error、empty、content

本篇看点
  • 阅读目标:用明确状态模型表达 loading、error、empty、content,减少散乱 boolean。
  • 核心问题:网络页面先建状态模型,再渲染 UI,而不是请求成功后直接塞数组。
  • 对比迁移:对应 Flutter AsyncValue/Bloc State 和 iOS ViewState/Result。
前言
网络列表不是"请求成功后展示数组"这么简单。真实页面至少有四态:loading、error、empty、content。少任何一个,用户体验都会不完整。
Flutter 里你可能会用 AsyncSnapshot、Bloc state、Riverpod 的 AsyncValue。iOS 里你可能会建 ViewStateResult。HarmonyOS 里也应该先建状态模型,再写 UI。
一. 先定义页面状态
页面里堆几个布尔值时,很快会出现状态组合问题:
ts 复制代码
@State loading: boolean = false;
@State failed: boolean = false;
@State empty: boolean = false;
这种写法很容易出现互相矛盾:loading 和 failed 同时为 true,或者 items 有数据但 empty 还是 true。
更好的方式是用状态对象:
ts 复制代码
enum LoadStatus {
  Loading,
  Success,
  Empty,
  Failure
}

interface PageLoadState<T> {
  status: LoadStatus;
  data?: T;
  message?: string;
}
页面只根据 status 渲染:
ts 复制代码
if (this.state.status === LoadStatus.Loading) {
  LoadingView()
} else if (this.state.status === LoadStatus.Failure) {
  ErrorView({ message: this.state.message })
} else if (this.state.status === LoadStatus.Empty) {
  EmptyView()
} else {
  ContentList({ items: this.state.data ?? [] })
}
二. Repository 返回 Result,而不是直接抛给页面
网络请求失败可能来自很多地方:无网、超时、服务端错误、解析失败、业务错误码。页面更适合消费整理后的错误状态,而不是直接理解所有底层细节。
ts 复制代码
interface Result<T> {
  success: boolean;
  data?: T;
  message?: string;
  code?: string;
}
Repository 负责把底层错误统一成业务可理解的结果:
ts 复制代码
async loadArticles(): Promise<Result<Article[]>> {
  try {
    const response = await this.http.get<Article[]>('/articles');
    return { success: true, data: response };
  } catch (error) {
    return { success: false, message: '网络请求失败,请稍后重试' };
  }
}
这和 iOS 的 Result<T, Error>、Flutter 里的 Either/Result 是同一类工程习惯。
三. loading 分两种
首屏 loading 和局部 loading 可以分开建模。
首屏没有内容时,可以展示骨架屏或空白 loading。已有内容时刷新,更适合保留内容并展示局部刷新状态,否则体验会闪。
ts 复制代码
interface ListState<T> {
  items: T[];
  initialLoading: boolean;
  refreshing: boolean;
  loadingMore: boolean;
  errorMessage?: string;
}
资讯列表、发现分页、排行榜切 Tab,都可以用这种状态结构。
四. error 也要分层
错误页不是只有一个"请求失败"。至少分:
  1. 首屏失败:页面没有内容,需要占位和重试。
  2. 刷新失败:保留旧内容,提示刷新失败。
  3. 加载更多失败:底部显示重试,不影响已有列表。
  4. 详情失败:详情页展示错误和返回能力。
Flutter 中也常这样拆,比如 status == initialFailurestatus == loadMoreFailure;iOS 里会区分 empty view、toast、footer retry。
五. 为什么这件事适合做成练习
初学网络时,如果只写一个 fetch(),学习者会误以为网络就是 API 调用。真正有价值的练习,是让读者看到状态如何驱动 UI。
在练习页面里,网络列表可以模拟慢请求、失败、空数据、重试。到了真实 App,同样模型可以迁移到资讯列表、专辑详情和发现页分页。
六. 实践经验
第一,用多个 boolean 管页面状态,状态组合失控。
第二,首屏 loading 和刷新 loading 用同一种遮罩,页面一直闪。
第三,网络错误直接展示底层异常,用户看不懂。
第四,Repository 把 UI 文案写死,导致不同页面无法定制错误展示。
小结
网络请求的第一课不是 GET/POST,而是四态建模。只要状态设计清楚,UI、重试、缓存、分页都会顺很多。
下一篇我们继续网络列表,重点讲下拉刷新、上拉加载、竞态保护和分页边界。
今日练习
  1. 把一个网络页面改成 Loading/Success/Empty/Failure 四态。
  2. 让首屏失败展示错误页,刷新失败只提示,不清空旧内容。
  3. 给 Repository 返回统一 Result<T>,页面不直接处理底层异常。
相关推荐
用户593096009781 小时前
Flutter 鸿蒙化实战:open_app_settings 适配 OpenHarmony,一键跳转系统设置
harmonyos
贾伟康1 小时前
【HarmonyOS 7新能力|047】ModularObjectExtensionAbility工程封装:把接入逻辑放进可维护的分层结构
harmonyos·arkts·模块化架构·跨应用调用·abilitykit
李游Leo2 小时前
HarmonyOS 7 ArkTS 并发实战:Sendable、共享模块与跨线程对象传递机制
harmonyos
骑着蜗牛撵大象3273 小时前
从跨平台Linux到鸿蒙PC:基于Qt C++的Flameshot截图工具源码级适配
harmonyos·鸿蒙·es
威哥爱编程5 小时前
HarmonyOS 7 空间音频实战:降噪、美化、变声、空间渲染的节点编排
华为·harmonyos·arkts
威哥爱编程5 小时前
HarmonyOS 7 视觉 AI 实战:系统级场景化控件,低门槛接入端侧视觉能力
华为·harmonyos·arkts
贾伟康5 小时前
【HarmonyOS 7新能力|046】智慧手势工程封装:把接入逻辑放进可维护的分层结构
人机交互·harmonyos·arkts·arkui·手势识别
贾伟康6 小时前
【HarmonyOS 7新能力|050】Core File Kit mmap工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·文件系统·mmap
贾伟康6 小时前
【HarmonyOS 7新能力|048】Taihe IPC工程封装:把接入逻辑放进可维护的分层结构
harmonyos·arkts·ipc·分布式通信·taihe