React 管理端库存与报价列表:扫码状态、分页与请求竞态
本文目录
本文根据一个个人机车零售管理端的默认分支源码做静态审阅。界面使用 React、TypeScript、Ant Design 与 Axios,状态分布在页面组件和 Zustand store,数据请求由独立 API 模块封装。这里只总结可复用的工程经验,不保留仓库名、服务地址、接口路径、真实客户数据或环境配置。没有安装依赖、运行构建、登录系统或操作真实库存;文中指出的是源码可见的实现和风险,不代表已复现的线上故障。
管理工作流由哪些界面组成
库存页把流水列表、商品筛选、日期范围、分页、批量入库/出库、条码扫描、手工补录和记录编辑放在同一工作台。扫码弹窗会在打开时清空本轮历史并聚焦输入框,回车后提交条码,再把焦点放回扫描输入;服务端返回低库存信息时,页面展示补货提醒。报价页提供状态与关键词筛选、分页、详情查看和状态推进。资源 API 按商品、配件、库存、报价等领域分组,页面不必直接拼接整站请求地址。
这些页面的难点不只是表格渲染,而是多个请求并行时,界面状态仍要解释清楚:当前筛选对应哪次查询、扫描结果是否全部出现、批量操作部分失败时哪些条目成功,以及用户个人信息是否只对有权限的人展示。可把每个交互看成一条明确命令,并让界面反馈与服务端最终结果对齐。
扫码历史要用函数式状态更新
条码可能连续快速到达,而请求的网络耗时并不固定。源码中的扫码成功和失败回调以当前 render 捕获的 scanHistory 拼接新数组。若两个扫码请求同时开始,它们可能都基于同一份旧历史创建结果;后返回的回调整体写回后,先完成的那一条就可能从弹窗历史中消失。这是根据闭包和异步回调推断出的竞争风险,尚未在运行环境中复现。
对纯追加事件,应让 React 在提交更新时提供最新状态:
setScanHistory((history) => [
...history,
{ requestId, name, quantity, direction, success },
]);
每次扫描还应在请求开始时创建稳定的 requestId,把成功或失败结果关联回同一条操作。若业务要求严格按扫描顺序展示,可先按请求开始顺序创建 pending 项,再按 ID 更新状态;如果只关心完成顺序,则可以追加完成事件,但要在界面上说明这一点。不要让网络返回顺序暗中决定操作历史的含义。
扫码输入不应因为等待上一次请求而丢字符或重复提交。要明确允许并发扫描还是串行扫描:并发时保留每个请求的身份、条码和数量;串行时在请求期间禁用提交,并在失败后仍保留可重试信息。刷新库存列表与预警时,也要避免旧查询响应覆盖刚执行完的新操作结果。
搜索重置页码时避免读取旧闭包
报价页的搜索处理器先调用 setPage(1),紧接着又调用当前闭包中的 fetchList()。React 的状态更新不会同步改写当前函数捕获的 page,因此从第二页或更后页搜索时,这个直接请求仍可能发往旧页;随后新页码触发 Effect,又会发起另一次请求。如果旧请求较晚返回,还可能覆盖新条件下的列表。
更清晰的实现是把输入草稿和已提交查询条件分开:点击搜索只提交过滤条件并把页码设为 1,由唯一的数据加载入口根据完整查询键请求。若必须从事件处理器立即请求,就显式构造 { page: 1, keyword, status },不要调用捕获旧页码的函数。每次加载使用递增序号或 AbortController;只有最新查询有权更新 rows、total、error 和 loading 状态。取消请求可以减少无用工作,序号校验则能拦住已完成或无法取消的旧响应。
筛选变化、清空筛选、刷新与分页应共享同一套查询参数构造逻辑。搜索关键词最好在输入框中作为草稿,用户点击搜索或回车后才成为已提交条件;否则每个按键都触发服务端请求,容易造成多余查询和结果闪烁。页面页码、筛选值与 URL 查询参数是否同步,应按产品是否需要可分享链接来决定,而不是在各控件里分别实现。
个人信息和授权不要交给表格组件
报价详情包含联系电话、车牌、车型和备注等可能识别个人的信息。前端应按角色和工作需要最小化展示,列表只保留处理任务必需字段,详情页再按权限展开;复制、导出、截图和客户端日志也要考虑这些字段。服务端应记录必要的管理操作审计,但不应把令牌、完整请求体或不必要的个人字段写入普通日志。
路由守卫、隐藏按钮与角色下拉框只负责界面体验,不构成 API 授权。库存调整、报价状态变更和敏感字段查询都必须由服务端重新验证操作者、角色和资源权限。前端传来的 ID、状态、总额和角色都不可信。测试时应分别覆盖未登录、身份有效但无权、管理员与最小权限角色,确认服务端直接请求同样遵守边界。
针对性验收清单
- 在慢网下连续扫描多件商品,并让请求以不同顺序返回;核对每个条码、数量、成功/失败结果均可追踪,刷新后的库存与流水一致。
- 从第 3 页输入新关键词并搜索,延迟旧条件请求;确认最终页码为 1,旧响应不会覆盖新结果,loading 状态也不会被早到的请求提前清除。
- 清空关键字或日期范围后检查查询参数,确认没有残留上次筛选;服务端返回空列表、部分失败和网络超时时,已输入的可重试信息仍保留。
- 使用普通角色与管理员分别查看报价详情,确认个人信息和库存写入能力由服务端控制,而不是只由前端按钮决定。
- 对空值、非法数量、重复提交、扫描焦点丢失和组件卸载时的迟到响应做回归,并为请求与结果记录不含隐私的关联 ID。
以上是源码级复盘,不是构建、浏览器或生产验收结论。推荐修复后再通过自动化测试和真实浏览器验证,尤其要包含并发请求的可控延迟测试。
参考:React useState 函数式更新、React Effect 与请求清理、MDN AbortController、OWASP Authorization Cheat Sheet。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。