React多文件上传时异步更新数组单个元素却覆盖全量状态问题
多文件上传进度状态覆盖问题解决方案
问题根因
该问题属于React常见的状态闭包陷阱:updateFileUploadProgress 函数在定义时会捕获当前渲染周期的selectedFiles状态值。第一个文件的上传进度触发状态更新后,组件会重新渲染生成新的updateFileUploadProgress函数,但之前已经触发的其他文件上传逻辑里,引用的还是初始渲染时绑定的旧函数,旧函数内部捕获的selectedFiles仍是初始状态值,因此每次更新都会覆盖其他文件已更新的进度。
修复方案
1. 核心修改:将状态更新改为函数式写法
修改updateFileUploadProgress,使用setState的函数式更新形式,直接从参数中获取最新的状态值,避免依赖闭包中的旧状态:
const updateFileUploadProgress = (fileName: string, progress: number) => { setSelectedFiles(prevFiles => { const currentObjectIndex = prevFiles.findIndex((x) => x.file.name === fileName); // 边界处理:未找到对应文件时直接返回原状态 if (currentObjectIndex < 0) return prevFiles; const newState = [...prevFiles]; newState[currentObjectIndex] = { ...newState[currentObjectIndex], currentProgress: progress }; return newState; }); };
2. 可选优化:上传任务异步处理优化
原sendFilesHandler中使用map遍历异步函数但未处理返回的Promise数组,存在异步逻辑隐患,可修改为如下形式:
const sendFilesHandler = async () => { // 如需等待所有文件上传完成后执行后续逻辑,用Promise.all包裹 await Promise.all(selectedFiles.map(async (file) => { const fileType = file.file.type.split('/')[0]; const formData = new FormData(); formData.append(fileType, file.file); formData.append('filename', file.file.name); await uploadFile(formData, updateFileUploadProgress); })); // 此处可添加上传完成的业务逻辑,如成功提示、状态重置等 };
原理解释
setState的函数式更新入参prevFiles永远指向当前最新的状态值,不依赖当前渲染闭包中的状态,无论何时触发进度更新,都能基于最新的文件列表修改对应文件的进度,不会出现覆盖其他文件进度的问题。
内容的提问来源于stack exchange,提问作者Pelicer
相关产品推荐
相关产品推荐

