You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript拖拽文件夹遍历后无法访问数组元素求助

拖拽文件夹遍历后无法访问数组元素的问题解决

问题场景

在React拖拽组件中实现了traverseDirectory函数用于递归遍历文件夹获取文件,但调用后出现以下异常:

  • 打印数组对象时能看到有元素,但直接访问数组长度、具体元素时返回空或undefined
  • 尝试用useState更新数组或直接修改数组均无效

函数代码

export const traverseDirectory = (
    directory: any,
    file_array:File[],
    path_array:string[]
) => {
    const reader = directory.createReader();
    reader.readEntries((entries: any) => {
        entries.forEach((entry: any) => {
            if (entry.isFile) {
                path_array.push(entry.fullPath);
                entry.file((file: File) => {
                    file_array.push(file);
                });
            } else if (entry.isDirectory) {
                traverseDirectory(entry,file_array,path_array);
            }
        });
    });

    return {
          'files': file_array,
          'paths': path_array,
        }
};

调用代码

const items = event.dataTransfer.items;
const entry = item.webkitGetAsEntry();
if (entry) {
// Recursively traverse the directory and collect files
 const data = traverseDirectory(entry, folderFiles, relativePaths);
//1
console.log(data)
//2
console.log(data.files);
//3
console.log(data.files.length);
//4
console.log(data.files[0]);
}

问题根源

核心原因是异步操作未完成就返回了结果:

  • reader.readEntries是异步API,它的回调函数会在浏览器读取完目录条目后才执行
  • entry.file同样是异步API,获取文件对象的回调也是延迟执行的

当traverseDirectory返回{files: file_array, paths: path_array}时,两个异步回调都还没执行,此时数组是空的。而浏览器的console会对引用类型做“懒更新”——打印的时候显示的是数组最终的状态,但代码执行到console.log(data.files.length)时,数组确实还是空的。

解决方案

将函数改造为基于Promise的异步函数,确保所有异步操作完成后再返回结果:

修改后的traverseDirectory函数

export const traverseDirectory = async (directory: any): Promise<{files: File[], paths: string[]}> => {
    const file_array: File[] = [];
    const path_array: string[] = [];

    // 封装readEntries为Promise
    const readEntries = (reader: any): Promise<any[]> => {
        return new Promise((resolve) => {
            reader.readEntries((entries: any[]) => {
                resolve(entries);
            });
        });
    };

    // 封装entry.file为Promise
    const getFile = (entry: any): Promise<File> => {
        return new Promise((resolve) => {
            entry.file((file: File) => {
                resolve(file);
            });
        });
    };

    const entries = await readEntries(directory.createReader());
    for (const entry of entries) {
        if (entry.isFile) {
            path_array.push(entry.fullPath);
            const file = await getFile(entry);
            file_array.push(file);
        } else if (entry.isDirectory) {
            // 递归遍历子目录,合并结果
            const subDirResult = await traverseDirectory(entry);
            file_array.push(...subDirResult.files);
            path_array.push(...subDirResult.paths);
        }
    }

    return { files: file_array, paths: path_array };
};

修改后的调用代码(React中)

// 假设在事件回调中,比如onDrop
const handleDrop = async (event: React.DragEvent) => {
    event.preventDefault();
    const items = event.dataTransfer.items;
    for (const item of items) {
        const entry = item.webkitGetAsEntry();
        if (entry && entry.isDirectory) {
            const data = await traverseDirectory(entry);
            // 此时可以正常访问数组元素
            console.log(data.files.length);
            console.log(data.files[0]);
            // 如果需要更新组件状态
            // setFolderFiles(data.files);
            // setRelativePaths(data.paths);
        }
    }
};

关键说明

  • 用Promise封装所有异步API,确保递归和文件读取操作按顺序完成
  • 使用async/await让异步代码看起来像同步代码,避免回调地狱
  • React中更新状态时,要在异步操作完成后调用setState,确保状态更新基于最新的数组结果

内容的提问来源于stack exchange,提问作者TSS Predator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 13:43:10