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

PReact中subFolders状态变更时useEffect未触发,无法递归读取Google Drive子文件夹

问题根因
  • 闭包陷阱导致状态更新异常:你在getFilesFromFolder中调用setSubFolders、setImageList时,直接使用了当前函数作用域捕获的旧状态值,多组异步请求同时返回时状态更新会相互覆盖,最终subFolders的实际更新结果不符合预期,甚至看起来没有发生变更,因此依赖subFolders的useEffect不会触发。
  • 子文件夹重复遍历:当前useEffect逻辑每次subFolders更新就遍历全部元素,已经处理过的子文件夹会被重复调用接口,打乱递归逻辑。
修正方案

核心修改两点:

  1. 状态更新改用函数式写法,直接读取最新的前序状态,规避闭包问题
  2. 新增已处理文件夹标记集合,避免同一个文件夹被重复请求
const [imageList, setImageList] = useState([]) as any;
const [subFolders, setSubFolders] = useState([]) as any;
// 新增已处理文件夹ID集合,避免重复调用
const [processedFolderIds, setProcessedFolderIds] = useState<Set<string>>(new Set())

const getFilesFromFolder = (fileId: string) => {
    let noToken = false;
    
    const requestFunction = ((pageToken?: string) => {
        gapi.client.drive.files.list({
            q: `'${fileId}' in parents`,
            pageToken
        }).execute((res: any) => {    
            const token = res.nextPageToken ?? null;

            const images = res.files.filter((file: any ) => 
            file.mimeType === 'image/jpeg' ||
            file.mimeType === 'image/png' ||
            file.mimeType === 'image/jpg'
            );
            
            // 状态更新改用函数式写法,获取最新的前序状态
            setSubFolders(prev => [...prev, ...res.files.filter((file: any ) => file.mimeType === 'application/vnd.google-apps.folder')]);
            setImageList(prev => [...prev, ...images])

            if (token) {    
                requestFunction(token);
            } else {
                noToken = true;
            }
        }).catch((err: any) => {
            console.log('err', err)
        })
    });

    if (!noToken) {            
        requestFunction();
    }
}

useEffect(() => {
    // 仅处理未遍历过的子文件夹
    const unprocessedFolders = subFolders.filter(folder => !processedFolderIds.has(folder.id))
    if (unprocessedFolders.length <= 0) return

    // 标记为已处理
    setProcessedFolderIds(prev => {
        const newSet = new Set(prev)
        unprocessedFolders.forEach(folder => newSet.add(folder.id))
        return newSet
    })

    unprocessedFolders.forEach((subFolder: any) => {
        getFilesFromFolder(subFolder.id);
    });
}, [subFolders, processedFolderIds])

// 组件挂载时调用根文件夹的遍历逻辑,替换为你的根文件夹ID
useEffect(() => {
  getFilesFromFolder('你的根文件夹ID')
}, [])

修正后状态每次更新都会生成全新的数组引用,subFolders变更后会正常触发依赖它的useEffect,递归逻辑也不会重复调用接口。

内容的提问来源于stack exchange,提问作者Sergiu Tonț

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 04:06:04