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

React自定义钩子调用无效错误求助及代码排查

解决React钩子调用错误:Invalid hook call

错误核心原因

你触发错误的直接原因是违反了React Hook的调用规则:在组件的handleSubmit事件回调内部调用了useStorage和useUpdateUser钩子。React要求所有钩子必须直接在函数组件的顶层作用域调用,禁止在事件处理函数、循环、条件判断或嵌套函数内调用。

分步解决方案

1. 重构钩子调用位置

将useStorage和useUpdateUser移到组件顶层,通过状态变化触发逻辑,而非在提交函数内调用:

修改ProfileDataForm.jsx:

const ProfileDataForm = () =>{
    const [formValues , setFormValues] = useState(userExample);
    // 把useStorage移到组件顶层,依赖formValues中的文件状态
    const {progress: progressPhoto, url: urlPhoto, error: errorPhoto} = useStorage(formValues.photo, "ejem.jpeg", "images/userPhotos");
    const {progress: progressPdf, url: urlPdf, error: errorPdf} = useStorage(formValues.inscriptionComprobant, "ejem.pdf", "pdfs/inscriptionComprobant");
    // 重构useUpdateUser,返回可执行的更新函数
    const [newDoc, updateError, updateUser] = useUpdateUser();

    const handleSubmit = async (event) => {
        event.preventDefault();
        const uid = "e9O4OfTsNRfPITvtcsF97YgMaYT2";

        // 等待文件上传完成,获取到URL后执行更新
        if(urlPhoto && urlPdf && !errorPhoto && !errorPdf){
            await updateUser(uid, {
                ...formValues,
                photo: urlPhoto,
                inscriptionComprobant: urlPdf
            });
            // 根据更新结果调整状态
            // setFormValues(updatedDoc);
        }
    }

    // 其余代码保持不变
}

2. 修复uploadFile参数顺序错误

你的useStorage中调用uploadFile(file, fileName, folderPath),但uploadFile的定义参数顺序是(folderPath, fileName, file),完全颠倒会导致上传路径错误:

修改uploadFile.js:

export const uploadFile = (file, fileName, folderPath) =>{
    // 路径添加斜杠分隔,避免拼接错误
    const storageRef = ref(storage, `${folderPath}/${fileName}`);
    const uploadTask = uploadBytesResumable(storageRef, file);
    return uploadTask;
}

3. 重构useUpdateUser钩子

useUpdateUser同样不能在回调内调用,需改成返回可执行的更新函数:

示例重构后的useUpdateUser:

export function useUpdateUser(){
    const [newDoc, setNewDoc] = useState(null);
    const [updateError, setUpdateError] = useState(null);

    const updateUser = async (uid, data) => {
        try {
            const doc = await updateDocument(uid, data);
            setNewDoc(doc);
            setUpdateError(null);
            return doc;
        } catch (err) {
            setUpdateError(err);
            throw err;
        }
    }

    return [newDoc, updateError, updateUser];
}

4. 优化useStorage的上传状态管理(可选)

添加上传状态和清理逻辑,提升用户体验和代码健壮性:

修改useStorage.js:

export function useStorage(file, fileName, folderPath){
    const [progress, setProgress] = useState(0);
    const [error, setError] = useState(null);
    const [url, setUrl] = useState(null);
    const [isUploading, setIsUploading] = useState(false);

    useEffect(() => {
        if (!file) return;

        setIsUploading(true);
        setError(null);
        setUrl(null);

        const uploadTask = uploadFile(file, fileName, folderPath)
            .on("state_changed",
                (snapshot) => {
                    const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
                    setProgress(progress);
                },
                (error) => {
                    setError(error);
                    setIsUploading(false);
                },
                async () => {
                    try {
                        // 注意:使用当前uploadTask的snapshot,而非uploadFile函数
                        const downloadURL = await getFileUrl(uploadTask.snapshot.ref);
                        setUrl(downloadURL);
                    } catch (err) {
                        setError(err);
                    } finally {
                        setIsUploading(false);
                    }
                }
            );

        // 组件卸载时取消上传
        return () => uploadTask.cancel();
    }, [file, fileName, folderPath]);

    return { progress, url, error, isUploading };
};

额外检查项

  • 检查React版本一致性:执行npm ls react react-dom,确保两者版本完全匹配
  • 移除重复React副本:若依赖树中存在多个React版本,删除node_modules和package-lock.json后重新安装依赖

内容的提问来源于stack exchange,提问作者Juan Pablo SR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 15:06:47