Skip to content

093. 前后置钩子、列配置钩子与选择模块

学习目标

这一节把事件钩子继续扩展到请求前后,并完成索引列、单选、多选模块。

学完后,你应该能理解:

  • 查询、新建、更新、删除为什么需要前后置钩子;
  • 事件钩子为什么要支持异步和抛错;
  • 如何在编辑状态下阻止查询;
  • 列配置钩子变量如何让模块追加列;
  • 为什么列计算要尽量放到更晚的渲染阶段;
  • 索引列、单选、多选模块分别解决什么问题。

请求前后置钩子

前面已经有行点击和行双击事件钩子。

这一节继续增加请求相关钩子。

包括:

  • 查询前;
  • 查询后;
  • 新建前;
  • 新建后;
  • 更新前;
  • 更新后;
  • 删除前;
  • 删除后。

这些钩子让其他模块可以在请求前后插入逻辑。

例如校验状态、修改请求参数、记录日志、刷新选中数据。

钩子支持异步

请求前后置钩子需要支持异步。

原因是有些动作不是同步完成的。

例如:

  • 请求前弹窗确认;
  • 请求前检查权限;
  • 请求前调用接口生成签名;
  • 请求后刷新其他模块数据。

所以执行钩子时使用 await

这样模块可以返回 Promise。

钩子可以阻断流程

前置钩子可以抛错。

一旦抛错,后面的请求就不继续执行。

例如表格正在编辑时,不允许重新查询。

可以在查询前钩子里判断:

ts
if (autoTable.state.isTableEditing) {
  throw new Error("请先保存数据再查询")
}

这样用户在编辑状态下翻页或查询时,会被阻止。

这比在每个按钮里写判断更统一。

编辑时不允许查询

如果正在编辑或新建数据,直接翻页会有风险。

未保存数据可能丢失。

所以这一节用 beforeLoad 钩子阻止查询。

当表格处于编辑状态时,翻页和重新加载会抛出提示。

用户保存或取消后,才能继续查询。

这是前端保护数据的一层规则。

新建和更新的前后置

保存时要区分新建和更新。

如果是新建数据,就执行新建前置和新建后置。

如果是已有数据,就执行更新前置和更新后置。

这让模块能分别处理两种场景。

例如:

  • 新建后默认选中新行;
  • 更新后刷新选中数据;
  • 新建前补默认字段;
  • 更新前校验版本号。

删除后置

删除后置也很重要。

如果某行被删除,而它正好在多选列表里,就要从选中数据里移除。

否则外部模块拿到的选中数据会包含已删除行。

所以删除完成后,需要通知选择模块同步状态。

这就是后置钩子的价值。

列配置钩子变量

列配置也改造成钩子变量。

它保存当前表格最终要渲染的列。

不同模块都可以往里面添加列。

例如:

  • 页面业务列;
  • 标准字段列;
  • 索引列;
  • 多选列;
  • 操作列;
  • 自动撑开列。

所有列最后统一排序和渲染。

标准字段列

如果项目要求所有表格都显示标准字段,可以通过模块统一添加。

例如:

  • ID;
  • 创建时间;
  • 更新时间。

模块只需要往列配置钩子变量里 push 这些列。

所有使用这个表格的页面都会出现这些字段。

这比每个页面手动复制列配置更稳定。

模块顺序与列计算

列配置来自多个模块。

如果某个模块太早用 useMemo 计算最终列,后面模块再 push 列就来不及了。

这会导致后添加的列不显示。

解决方式是把最终列计算放到更晚的阶段。

课程里把表格内容抽成子组件。

在子组件渲染时再计算列。

这样所有模块都已经完成注册,列配置更完整。

为什么子组件能解决问题

父级模块安装时,各个模块还在往钩子变量里追加列。

如果父级马上计算列,顺序会受模块执行影响。

子组件渲染发生得更晚。

它拿到的是本轮已经收集完成的列配置。

所以标准字段模块、索引列模块、多选列模块即使顺序靠后,也能进入最终列。

索引列模块

索引列被拆成独立列模块。

它负责显示当前行序号。

索引列通常有几个默认值:

  • 靠左;
  • 固定宽度;
  • 居中;
  • 标题为序号;
  • 顺序值很小,靠近表格最左侧。

索引列显示的不是当前页内索引。

它要结合分页信息计算全局序号。

例如第二页第一条,要显示对应的全局行号。

索引列和编辑态

索引列渲染时要注意编辑态。

非编辑状态和编辑状态传入的 record 可能不是同一个对象。

如果直接用编辑态表单数据去找索引,可能找不到。

所以索引列组件要使用正确的原始行数据来计算序号。

这是通用组件里很容易踩到的细节。

单选模块

单选模块维护当前选中行 ID。

它不直接保存整条行数据。

原因是行数据可能会更新。

如果保存整条对象,更新后还要同步它。

只保存 ID,则可以随时从最新表格数据里找到当前选中行。

这样选中行始终和表格数据保持一致。

自动选中第一行

数据加载完成后,单选模块会默认选中第一行。

原因是后续很多功能需要当前行。

例如:

  • 表单编辑;
  • 父子表查询;
  • 查看详情;
  • 外部按钮操作。

如果没有当前行,这些功能就要到处处理空状态。

默认选中第一行能让交互更连续。

单选显示

单选状态可以显示在索引列上。

当某行被选中时,索引列用主题色背景高亮。

点击其他行时,选中 ID 改变。

翻页后,加载完成再选中当前页第一行。

这就形成了基本单选体验。

多选模块

多选模块比单选复杂。

它要支持跨页选择。

如果只保存 ID,翻页后当前页数据可能不存在对应记录。

所以多选模块需要保存选中的行数据。

这带来额外同步问题。

当数据新增、更新、删除、重新加载时,选中数据也要同步。

多选状态同步

多选模块需要监听多个后置事件:

  • 加载后刷新选中数据;
  • 新建后同步新数据;
  • 更新后替换选中数据;
  • 删除后移除已删除数据。

如果不处理这些事件,选中数据会变旧。

例如用户选中一行后编辑保存。

外部拿到的选中行应该是更新后的数据,而不是旧数据。

多选列

多选模块会添加多选列。

如果配置开启多选列,就往列钩子变量里添加选择列。

选择列用于显示当前行是否选中。

点击行时,也可以根据配置触发选中或取消选中。

这比只靠 checkbox 更灵活。

全选、半选与反选

多选模块要计算当前页选择状态。

常见状态有:

  • 当前页全选;
  • 当前页全不选;
  • 当前页部分选中。

还要提供方法:

  • 全选当前页;
  • 取消当前页全选;
  • 选中或反选某一行。

这些能力为批量操作做准备。

为什么不用现成表格选择能力

Ant Design Table 自带选择功能。

但课程里的多选要结合:

  • 跨页选择;
  • 新建后同步;
  • 更新后同步;
  • 删除后同步;
  • 外部模块读取;
  • 自定义列和钩子体系。

这些需求超出了简单 rowSelection 的范围。

所以这里自己封装选择模块。

这一节的核心

这一节把表格从“能编辑”继续推向“能被模块联动”。

关键能力包括:

  • 请求前后置钩子;
  • 编辑状态阻止查询;
  • 列配置钩子变量;
  • 标准字段模块;
  • 索引列模块;
  • 单选模块;
  • 多选模块;
  • 多选数据的跨页与更新同步。

这些能力会继续支撑表单编辑、父子表、批量操作和更复杂的 AI 表格功能。

AI Agent 课程学习文档。