前端列表页状态处理

列表页不是只有“请求数据然后渲染”,而是要系统处理首次加载、刷新、空态、失败、分页和结果漂移。

#type / synthesis #status / growing #tech / dev / frontend #platform / browser

[!info] related notes

前端列表页状态处理

一句话定义

列表页状态处理就是把“拉列表”这件事拆成清晰的用户状态机,而不是只维护一个 loading 布尔值。

为什么列表页特别容易出问题

因为列表页通常同时叠了很多变量:

  • 首次加载
  • 搜索
  • 筛选
  • 排序
  • 分页或无限滚动
  • 空结果
  • 请求失败
  • 重试

如果这些状态没有拆开,用户很快就会看到:

  • 首次进入白屏
  • 搜索后闪空
  • 翻页时数据抖动
  • 加载失败后没有恢复入口
  • 新请求回来把旧请求结果覆盖

至少要分清的几种状态

1. 首次加载

这是用户第一次进入页面、页面还没有任何数据时的状态。

常见表现:

  • 骨架屏
  • 局部 loading
  • 表格占位行

这里一般不要直接渲染“暂无数据”,因为此时还不知道有没有数据。

2. 已有数据上的刷新加载

这类状态和首次加载要区分开。

区别在于:

  • 页面已经有旧数据
  • 现在只是根据新条件重新请求

更稳的做法通常是:

  • 保留旧数据
  • 在局部显示刷新中的提示
  • 避免整块内容瞬间清空造成闪烁

3. 空态

空态表示请求成功,但当前条件下没有结果。

好的空态至少要回答两件事:

  • 为什么没有内容
  • 用户下一步能做什么

例如:

  • 当前筛选条件下暂无数据
  • 清空筛选重新查看
  • 去创建第一条记录

4. 错误态

错误态表示这次请求没有成功完成。

除了报错文案,更重要的是恢复动作:

  • 重试按钮
  • 保留搜索词和筛选条件
  • 不要把用户刚才的操作上下文直接抹掉

5. 分页 / 加载更多

列表页往往不是一次请求完,而是持续翻页。

这时还要继续区分:

  • 正在加载下一页
  • 已经没有更多数据
  • 下一页加载失败但前面数据仍然可用

“第一页失败”和“第 N 页失败”不能用同一种 UI 处理。

一个更接近真实业务的状态机

可以把列表页粗分成:

  1. 初始态
  2. 首次加载中
  3. 成功且有数据
  4. 成功但为空
  5. 首次加载失败
  6. 已有数据时刷新中
  7. 下一页加载中
  8. 下一页加载失败
  9. 没有更多数据

这个拆法的意义是:

  • 页面能对用户说真话
  • 每种状态都有对应恢复路径

工程上最容易忽略的点

1. 查询条件变化时要重置分页

如果用户修改了搜索词或筛选条件,通常要把页码重置回第一页,否则会出现:

  • 上一套条件下的第 5 页
  • 套到新条件后直接查空

这不是“真没数据”,而是页码状态脏了。

2. 要防旧请求覆盖新请求

用户连续输入搜索词时,后发请求不一定后返回。

如果不做处理,就可能出现:

  • 用户已经搜 “abc”
  • 结果却被旧的 “a” 请求覆盖

常见处理手段包括:

  • 取消旧请求
  • 给请求打版本号
  • 只接收最后一次有效响应

3. 不要把刷新 loading 做成整页遮罩

列表已可读时,整页遮住会让体验变差。很多场景更适合:

  • 局部 loading
  • 顶部细条进度
  • 表头或按钮 loading

和后端 / SQL 的协作点

列表页状态不只是前端问题,还会和接口设计直接耦合:

  • 是否返回 total
  • 是否支持稳定排序
  • 分页是页码式还是游标式
  • 搜索和筛选参数如何表达

如果后端分页不稳定,前端再细致也会出现翻页重复或漏项。

面试里怎么答更像工程实现

可以直接说:

“列表页我不会只放一个 loading。至少会区分首次加载、已有数据时刷新、空态、错误态、加载更多和无更多数据;搜索筛选变化时会重置分页;并处理旧请求覆盖新请求的问题。这样页面在慢网和失败场景下也有稳定体验。”

最短记忆方式

  • 首次加载和刷新加载分开
  • 空态和错误态分开
  • 第一页失败和下一页失败分开
  • 搜索变了就重置分页
  • 防旧请求覆盖新请求
创建于 2026/5/7 更新于 2026/5/27