React实现深度嵌套文件夹上传时数组扁平化异常问题
问题分析
你的问题出在嵌套Promise解析后生成了多层嵌套数组,而Array.flat()默认只扁平化一层,深层的嵌套数组无法被展开。
看你的traverseDirectory函数:处理子目录时,它返回的Promise最终会解析为Promise.all(fileList)的结果——也就是一个包含File对象和子目录Promise解析结果的数组。当存在多层子目录时,这个结构会变成[File, [File, [File]]]这样的嵌套形式,仅用flat()只能展开最外层的数组,深层的嵌套数组依然保留。
解决方案
这里提供两种可行的修复方式:
方式一:使用flat(Infinity)彻底扁平化数组
这是最简单的修改,只需要把setFiles(files.flat())改成setFiles(files.flat(Infinity)),Infinity参数会让数组不管嵌套多少层都被完全扁平化为一维数组:
Promise.all(fileList).then((files) => { console.log(files, files.flat(Infinity)) setFiles(files.flat(Infinity)); });
方式二:重构traverseDirectory,直接收集所有File对象
如果不想依赖flat(Infinity),可以重构遍历逻辑,让traverseDirectory直接返回包含所有File对象的一维数组Promise,从根源避免嵌套结构。用async/await能让代码逻辑更直观:
const [files, setFiles] = useState([]); const handleDropFile = async (event) => { event.preventDefault(); const items = event.dataTransfer.items; const fileList = []; for (let i = 0; i < items.length; i++) { const entry = items[i].webkitGetAsEntry(); if (entry.isFile) { fileList.push(entry.file()); } else if (entry.isDirectory) { fileList.push(...await traverseDirectory(entry, entry.name + "/")); } } const allFiles = await Promise.all(fileList); setFiles(allFiles); }; const traverseDirectory = async (directory, currentPath) => { const reader = directory.createReader(); const fileList = []; const readEntries = async () => { const entries = await new Promise(resolve => reader.readEntries(resolve)); for (const entry of entries) { if (entry.isFile) { const file = await entry.file(); const modifiedFile = new File( [file], currentPath + file.name, { type: file.type } ); fileList.push(modifiedFile); } else if (entry.isDirectory) { const subFiles = await traverseDirectory(entry, `${currentPath}/${entry.name}`); fileList.push(...subFiles); } } if (entries.length > 0) { await readEntries(); } }; await readEntries(); return fileList; };
重构后的优势:
- 用
async/await替代嵌套Promise,代码逻辑更易读 traverseDirectory直接返回一维的File对象数组,不需要后续扁平化处理- 补上了原始代码中未调用
readEntries的隐性问题,确保目录遍历能正常执行
内容的提问来源于stack exchange,提问作者Doruk
相关产品推荐
相关产品推荐

