ReactJS实现DropBox式断点续传:localStorage状态存取问题
断点续传功能修复方案(React+Express)
核心问题分析
当前代码在断点续传实现上的关键问题:
- localStorage仅存储全局
uploadedChunks数组,未关联具体文件标识,无法区分不同文件的上传进度 - 页面加载时的状态恢复逻辑未匹配当前文件列表,直接读取的全局状态无法对应到单个文件
- 文件上传完成后未清理对应localStorage记录,导致同名文件上传时出现错误
修复步骤与代码修改
1. 重构localStorage存储结构,按文件唯一标识存储
用文件名+文件大小作为唯一标识,存储每个文件的已上传块列表和总块数,避免同名文件冲突:
// 在uploadChunk函数中修改存储逻辑 function uploadChunk(readerEvent) { const file = files[currentFileIndex]; const data = readerEvent.target.result; const fileSize = file.size; const isLastChunk = currentChunkIndex === Math.ceil(fileSize / chunkSize) - 1; // 生成文件唯一标识 const fileKey = `${file.name}-${fileSize}`; // 更新当前文件的已上传块 const updatedChunks = [...new Set([...(fileUploadStates[fileKey]?.uploadedChunks || []), currentChunkIndex])]; // 构建当前文件的上传状态 const fileState = { uploadedChunks: updatedChunks, totalChunks: Math.ceil(fileSize / chunkSize) }; // 合并已有状态,避免覆盖其他文件记录 const existingState = JSON.parse(localStorage.getItem("dropboxUploaderState")) || {}; const newState = { ...existingState, lastUploadedFileIndex: currentFileIndex, [fileKey]: fileState }; localStorage.setItem("dropboxUploaderState", JSON.stringify(newState)); setFileUploadStates(newState); // 原有上传逻辑... }
2. 修复页面加载时的状态恢复逻辑
匹配当前文件列表与localStorage存储的状态,恢复对应文件的上传进度:
// 替换原有的恢复useEffect useEffect(() => { const storedState = localStorage.getItem("dropboxUploaderState"); if (storedState && files.length > 0) { const parsedState = JSON.parse(storedState); let targetFileIndex = null; let targetChunkIndex = null; files.forEach((file, index) => { const fileKey = `${file.name}-${file.size}`; const fileState = parsedState[fileKey]; if (!fileState) return; // 文件已完成上传,标记状态 if (fileState.uploadedChunks.length === fileState.totalChunks) { file.finalFilename = parsedState.finalFilename || file.name; setLastUploadedFileIndex(index); } else { // 未完成,定位到最后一个已上传块的下一个 targetFileIndex = index; targetChunkIndex = fileState.uploadedChunks[fileState.uploadedChunks.length - 1] + 1; } }); if (targetFileIndex !== null) { setCurrentFileIndex(targetFileIndex); setCurrentChunkIndex(targetChunkIndex); } } }, [files]);
3. 维护单文件的已上传块校验
将全局uploadedChunks改为对象,存储每个文件的上传状态:
// 替换原有的uploadedChunks状态 const [fileUploadStates, setFileUploadStates] = useState({}); // 修改readAndUploadCurrentChunk中的校验逻辑 function readAndUploadCurrentChunk() { const file = files[currentFileIndex]; if (!file) return; const fileKey = `${file.name}-${file.size}`; const currentFileState = fileUploadStates[fileKey] || { uploadedChunks: [] }; const from = currentChunkIndex * chunkSize; const to = from + chunkSize; const blob = file.slice(from, to); // 跳过已上传的块 if (currentFileState.uploadedChunks.includes(currentChunkIndex)) { setCurrentChunkIndex(currentChunkIndex + 1); return; } const reader = new FileReader(); reader.onload = (e) => uploadChunk(e); reader.readAsDataURL(blob); }
4. 上传完成后清理localStorage记录
文件全部块上传完成后,移除对应文件的存储记录:
// 在uploadChunk函数的isLastChunk分支中添加 if (isLastChunk) { file.finalFilename = response.data.finalFilename; setLastUploadedFileIndex(currentFileIndex); setCurrentChunkIndex(null); // 清理当前文件的localStorage记录 const fileKey = `${file.name}-${file.size}`; const existingState = JSON.parse(localStorage.getItem("dropboxUploaderState")) || {}; delete existingState[fileKey]; localStorage.setItem("dropboxUploaderState", JSON.stringify(existingState)); }
内容的提问来源于stack exchange,提问作者Rohit W3Dev
相关产品推荐
相关产品推荐

