PReact中subFolders状态变更时useEffect未触发,无法递归读取Google Drive子文件夹
问题根因
- 闭包陷阱导致状态更新异常:你在
getFilesFromFolder中调用setSubFolders、setImageList时,直接使用了当前函数作用域捕获的旧状态值,多组异步请求同时返回时状态更新会相互覆盖,最终subFolders的实际更新结果不符合预期,甚至看起来没有发生变更,因此依赖subFolders的useEffect不会触发。 - 子文件夹重复遍历:当前useEffect逻辑每次
subFolders更新就遍历全部元素,已经处理过的子文件夹会被重复调用接口,打乱递归逻辑。
修正方案
核心修改两点:
- 状态更新改用函数式写法,直接读取最新的前序状态,规避闭包问题
- 新增已处理文件夹标记集合,避免同一个文件夹被重复请求
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ț
相关产品推荐
相关产品推荐

