加载进度条怎么在React里实时更新?

蒙蒙 阅读 10

我用React做文件上传,想显示一个进度条,但setState之后界面没反应。明明onUploadProgress回调里打印的progress是变化的,可UI就是不动。是不是我状态更新的方式有问题?

试过把progress设成state,也在axios的onUploadProgress里调用了setProgress,但进度条卡在0%不动。代码大概是这样:

const [progress, setProgress] = useState(0);

const uploadFile = () => {
  axios.post('/upload', file, {
    onUploadProgress: (e) => {
      const p = Math.round((e.loaded * 100) / e.total);
      setProgress(p); // 这里log出来是正常数字,但UI不更新
    }
  });
};
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
司空若兮
你的代码逻辑本身没问题,setState应该是会触发的。卡在0%不动最可能的原因是 e.total 为0或undefined,导致进度计算出来是NaN或者0。

onUploadProgress 回调里先打个log确认一下:

onUploadProgress: (e) => {
console.log('loaded:', e.loaded, 'total:', e.total);
const p = Math.round((e.loaded * 100) / e.total);
setProgress(p);
}


如果total是0或者undefined,那就是后端的问题了——服务器没有在响应头里返回Content-Length,axios拿不到文件总大小。

解决办法有两个:

一是让后端在响应头里加上 Content-Length。二是如果后端实在不返回,你只能做个假的进度条,比如用setInterval模拟一下,或者直接显示“上传中...”而不显示具体百分比。

另外提醒一下,useState的更新在快速连续调用时可能会被React批量处理导致不生效,不过你这个场景应该不至于。如果确认total有值还是不动,可以试试用函数式更新:

setProgress(() => Math.round((e.loaded * 100) / e.total))


先排查total的值吧,大概率是这个问题。
点赞
2026-03-11 14:23