Skip to content

034. 前端工具函数、Hook 与详情页流程 ​

学习目标 ​

这一节开始实现 AI 简历前端的基础工具和 Hook。

学完后,你应该能理解:

  • utils 和 hooks 为什么要分开;
  • AI 模型配置为什么先写在前端;
  • 枚举工具如何生成 Select 选项;
  • DOM 导出 PDF 依赖什么能力;
  • 文件选择、图片预览和 base64 转换怎么配合;
  • 动态加载 UMD 静态库解决什么问题;
  • 为什么需要稳定回调 Hook;
  • 详情页为什么要先生成 ID 再编辑。

utils 和 hooks 分层 ​

前端项目里会建立两个目录。

目录放什么
utils和框架无关的工具函数
hooksReact 相关的 Hook 函数

utils 里的函数不应该依赖 React。

例如:

  • 文件处理;
  • 图片判断;
  • 字符串转换;
  • PDF 导出;
  • 枚举转换。

hooks 里才放和 React 状态、生命周期、表单、路由有关的逻辑。

这种分层能让工具函数更容易复用。

AI 模型配置 ​

AI 简历里会有模型选择。

前端需要展示模型选项,例如模型名称和模型值。

更正式的做法是把模型配置放到数据库里:

  • 模型标识;
  • 显示名称;
  • 平台;
  • 是否启用;
  • 排序;
  • 价格或备注。

因为模型配置会经常读取,还可以配 Redis 缓存。

当前为了先推进功能,模型选项先写在前端配置文件里。

这不是最完整的企业级做法,但足够支撑学习项目。

枚举转 Select 选项 ​

前端经常需要把枚举配置转成 Select 组件需要的选项。

Select 通常需要:

ts
[
  { label: '显示名称', value: '实际值' }
]

所以可以封装工具,把模型枚举、状态枚举等统一转换成 Select options。

这样组件里只关心渲染,不需要每次手写转换逻辑。

DOM 导出 PDF ​

AI 简历需要把页面里的某个 DOM 节点导出成 PDF。

项目会封装 exportElementToPDF 这类工具。

它接收一个 DOM 元素,然后调用第三方库生成 PDF。

这里要注意依赖问题。

有些 PDF 导出库依赖 GitHub 仓库里的包,国内环境安装时可能下载失败。

课程里使用重新打包后的包,避免安装时去拉取难下载的 GitHub 依赖。

文件选择工具 ​

浏览器里选择文件,本质上还是通过 input type="file"。

工具函数可以把这个动作封装起来,让业务代码只调用:

  • 选择单个文件;
  • 选择多个文件;
  • 限制文件类型;
  • 拿到 File 对象数组。

这和 Ant Design Upload 组件底层思路类似。

前端不能直接“打开本地文件系统”,只能通过用户选择文件拿到浏览器允许访问的 File 对象。

图片 base64 预览 ​

用户选择图片后,前端拿到的是 File 对象。

这个对象不能直接塞给 <img> 的 src。

如果要本地预览,可以把 File 转成 base64。

在 AI 对话里,图片也可以用两种方式传给多模态模型:

  • 图片网络地址;
  • base64 图片内容。

当前聊天消息不长期保存,所以适合用 base64 方式把图片传给模型。

只支持图片消息 ​

当前上传消息先只处理图片。

如果用户选择 PDF、TXT、Word 等文件,需要额外解析文件内容。

这些解析可以放在前端,也可以放在后端,但会引入更多依赖和复杂度。

所以当前阶段先用工具函数判断是否图片。

不是图片时,直接提示用户。

动态加载静态库 ​

AI 简历前端会用到一些比较大的静态库,例如代码编辑器相关资源。

这些库不一定要在页面初始化时全部加载。

可以通过动态加载脚本的方式,在需要时再加载。

好处是:

  • 首屏更轻;
  • 不需要一次加载所有大文件;
  • 可以控制版本;
  • 更新静态库时只改配置和版本号;
  • 避免浏览器缓存旧文件。

这类资源通常以 UMD 形式通过 script 标签加载。

为什么要预加载编辑器资源 ​

代码编辑器加载比较慢。

如果用户点击到代码编辑区域时才开始加载,体验会有明显等待。

所以可以在某些页面提前预加载编辑器资源。

这样用户切到代码编辑时,编辑器能更快显示。

这是一种性能体验优化。

稳定回调 Hook ​

React 里经常会遇到异步函数和闭包问题。

普通 useCallback 需要写依赖数组。

但有些函数希望引用稳定,同时内部又能拿到最新状态。

项目会封装类似 useStableCallback 的 Hook。

它的目标是:

  • 函数引用保持稳定;
  • 避免不必要的重新渲染;
  • 异步逻辑里尽量拿到最新值;
  • 减少依赖数组带来的反复重建。

这类 Hook 和一些组件库里的 useEvent 思路接近,但命名更贴近 React 的回调语义。

生成 ID 的 Hook ​

前端有时需要先拿到一个后端 ID。

项目会封装 useId 之类的 Hook,调用后端接口生成 ID。

后端生成 ID 的方式来自数据库,能更好保证唯一性。

这比前端自己随机生成 ID 更适合业务数据。

为什么新建页要先有 ID ​

有些业务场景需要先有主表 ID,再处理子数据。

例如报销单:

  • 先有报销单 ID;
  • 子表里的备用金、附件、明细都要挂到这个 ID 上。

AI 简历也类似。

用户新建简历时,可能先上传职业照或附件,这些文件需要知道属于哪份简历。

所以进入新建页时,可以先生成一个 ID,再围绕这个 ID 编辑。

new 路由和真实 ID ​

详情页可以先进入 new 状态。

页面发现 ID 是 new 时:

  1. 调用后端生成真实 ID;
  2. 重定向到带真实 ID 的详情页;
  3. 再加载或初始化这条记录。

这样页面后续一直围绕真实 ID 工作。

如果这个 ID 对应的数据已经保存过,就加载已有数据;如果没保存过,就按新建状态处理。

当前做法的缺陷 ​

如果用户手动输入一个随便的 ID,系统可能也会当成新数据保存。

更严谨的做法是后端在新建时检查 ID 来源和合法性。

当前先把主流程跑通,后续可以再增强 ID 校验。

新建默认值 ​

新建简历时,页面可以提供默认数据。

例如:

  • 默认模板源码;
  • 默认简历文案;
  • 默认主题色;
  • 默认表单字段。

这些默认值可以通过 getNewRecord 之类的函数返回。

这样用户进入新建页时不是空白,而是有一个可编辑起点。

详情页状态 ​

详情页 Hook 会管理很多状态。

例如:

  • 当前是新建还是更新;
  • 是否正在初始化;
  • 是否已经加载过;
  • 当前数据对象;
  • 是否正在保存;
  • 请求错误信息;
  • Ant Design 表单对象;
  • 重新加载方法。

把这些逻辑封装成 Hook,页面组件会清爽很多。

这一节的重点 ​

这一节搭的是 AI 简历前端地基。

你需要理解:

  • 普通工具放 utils;
  • React 状态逻辑放 hooks;
  • 文件、图片、PDF、动态脚本都先封装;
  • 复杂详情页要有统一新建和编辑流程;
  • 很多业务需要先生成 ID 再编辑。

后面真正写 AI 简历页面时,这些工具会不断被调用。

AI Agent 课程学习文档。