PReact useEffect 不会触发状态更改

PReact useEffect doesn't trigger on state change

我想做一个递归函数,基本上每次文件夹下有一个子文件夹时都会运行,这样我就可以从所有可用的子文件夹中获取所有内容。

不确定我在这里遗漏了什么,但是子文件夹的状态更改不会触发将其作为依赖项的 useEffect:

    const [imageList, setImageList] = useState([]) as any;
    const [subFolders, setSubFolders] = useState([]) as any;

    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 && res.nextPageToken || null;

                const images = res.files.filter((file: any ) => 
                file.mimeType === 'image/jpeg' ||
                file.mimeType === 'image/png' ||
                file.mimeType === 'image/jpg'
                );
                
                setSubFolders([...subFolders, ...res.files.filter((file: any ) => file.mimeType === 'application/vnd.google-apps.folder')]);
                setImageList([...imageList, ...images])

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

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

    useEffect(() => {
        if (subFolders && subFolders.length > 0) {
            subFolders.forEach((subFolder: any) => {
                getFilesFromFolder(subFolder.id);
            });
        }
    }, [subFolders])

由于您基本上是在遍历文件结构并将状态更新排队,所以我假设您遇到的任何问题都是因为您使用的是正常状态更新。当这些在循环中排队或在渲染周期内多次排队时,它们会覆盖先前排队的更新。

要解决这个问题,您应该真正使用功能状态更新。这样每次更新都会正确地更新前一个状态, 而不是 前一个渲染周期的状态。这是一个微妙但重要的区别,并且经常被忽视。

Functional Updates

setSubFolders(subFolders => [
  ...subFolders,
  ...res.files.filter((file: any ) =>
    file.mimeType === 'application/vnd.google-apps.folder'
  ),
]);
setImageList(imageList => [...imageList, ...images]);