React useEffect文件上传后附件列表延迟更新问题
问题产生原因
3个核心bug叠加导致上传后列表延迟更新,删除操作不受影响:
- 后端查询接口逻辑错误:获取附件列表的GET接口仅在查询结果
result.length > 0时才返回响应,当查询结果为空时直接挂起请求不做任何返回。上传文件后存在毫秒级的数据库写入事务延迟,首次拉取列表的请求如果在事务提交前到达后端,会拿到空结果,请求就会一直挂起,直到后续请求查到非空结果才会响应;而删除操作后列表始终存在至少0条以上记录,只要项目下还有附件,查询结果的length就大于0,接口会正常返回,不会挂起。 - 前端useEffect依赖配置完全错误:将
attachmentList自身作为useEffect的依赖项,会触发无限循环请求——每次请求完成调用setAttachmentList更新状态,状态变化又触发useEffect重新执行发请求,这种无意义的轮询不仅浪费性能,还刚好撞上了后端接口空结果不返回的问题,要等好几轮轮询才能拿到插入完成后的非空结果,造成数秒延迟。 - 缺少操作完成后的主动刷新逻辑:删除、上传这类修改数据的操作完成后,没有主动触发列表重新拉取,完全依赖useEffect的被动触发,本身就不符合数据更新的交互逻辑。
另外你的Axios传参写法也有问题:Axios.get的第二个参数是请求配置项,query参数需要放在params字段下,你当前直接传对象的写法不会把参数带到请求里,只是因为你用了路径参数传projectId才没有报错。
可行修复方案
按顺序修复前后端问题即可解决延迟:
1. 修复后端查询接口逻辑
无论查询结果是否为空都正常返回响应,不要挂起请求,修正后的代码如下:
app.get("/:projectId/attachment", function(req, res){ const projectId = req.params.projectId; try{ const findProjectAttachment = "SELECT project_attachment.project_attachment_id, project_attachment.project_attachment_url, project_attachment.project_id FROM project_attachment INNER JOIN project ON project_attachment.project_id=project.project_id WHERE project_attachment.project_id = ?;"; db.query(findProjectAttachment, projectId, (err, result) => { if(err){ console.log(err); return res.status(500).send({error: "查询附件失败"}); } // 空数组也正常返回,不要判断length res.send(result); }) } catch(err){ console.log(err); res.status(500).send({error: "服务异常"}); } });
同时建议检查你的文件上传接口(/uplatt),确保文件写入磁盘、数据库插入记录都完成后再给前端返回成功响应,不要提前返回造成前端跳转时数据还没写入完成。
2. 修复前端useEffect的错误依赖
把拉取附件列表的逻辑抽成独立方法,仅在组件挂载、关联项目ID变化时触发请求,去掉会造成死循环的attachmentList依赖:
// 抽离独立的拉取方法,方便各处主动调用 const fetchAttachmentList = () => { Axios.get(`http://localhost:3001/${projectId}/attachment`) .then((response) => { setAttachmentList(response.data); }) .catch(err => console.error("获取附件列表失败", err)) } useEffect(()=>{ fetchAttachmentList(); // 仅依赖projectId,不要依赖attachmentList },[projectId]);
3. 增加操作完成后的主动刷新
在删除附件、上传附件这类修改操作完成后,主动调用fetchAttachmentList()拉取最新数据,不需要等轮询:
- 修复删除逻辑,删除成功后直接刷新列表:
const deleteAttachment = (e, attachment_id) => { e.preventDefault(); const attachmentId = attachment_id; Axios.delete(`http://localhost:3001/delattachment/${attachmentId}`, { params: {attachmentId: attachmentId} }) .then((respon) => { window.alert("Attachment has been deleted!"); // 主动刷新列表 fetchAttachmentList(); handleDelete2(); }) .catch(err => console.error("删除失败", err)) }
- 上传附件的场景,从AddAttachment页面跳回列表页时,组件如果没有重新挂载,可以通过react-router的路由状态、或者全局状态触发一次
fetchAttachmentList调用即可,不需要保留无限轮询的逻辑。
内容的提问来源于stack exchange,提问作者red17
相关产品推荐
相关产品推荐

