React项目中useSignInWithEmailAndPassword未抛出正确Firebase错误
问题分析与解决方案
核心问题
- API使用错误:
react-firebase-hooks提供的signInWithEmailAndPassword函数不返回Promise,你写的.then()和.catch()会直接执行,不会等待鉴权结果,这就是为什么无论输入是否正确都会进入.then()分支。 - 逻辑冗余且不严谨:用登录接口判断邮箱是否已存在完全没必要——Firebase注册接口本身会在邮箱已被使用时抛出明确错误,且你把
wrong-password错误直接等同于“邮箱已存在”的逻辑不严谨(邮箱未注册时会返回user-not-found错误,和密码错误是不同场景)。
正确实现方式
直接调用注册接口createUserWithEmailAndPassword,利用react-firebase-hooks提供的状态捕获错误即可:
import { AuthModalState } from '@/atoms/authModalAtom'; import { Input, Button, Flex, Text } from '@chakra-ui/react'; import React, { useState, useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { useCreateUserWithEmailAndPassword } from "react-firebase-hooks/auth" import { auth } from '@/firebase/clientApp'; import 'firebase/auth'; const SignUp: React.FC = () => { const setAuthModalState = useSetRecoilState(AuthModalState) const [signUpForm, setSignUpForm] = useState({ email:"", password: "", confirmPassword: "", }) const [notMatchedError, setNotMatchedError] = useState("") const [alreadyInUseError, setAlreadyInUseError] = useState("") const [ createUserWithEmailAndPassword, user, loading, userError, ] = useCreateUserWithEmailAndPassword(auth); // 监听注册错误状态 useEffect(() => { if (userError) { switch(userError.code) { case 'auth/email-already-in-use': setAlreadyInUseError("该邮箱已被注册"); break; case 'auth/invalid-email': setAlreadyInUseError("邮箱格式无效"); break; case 'auth/weak-password': setAlreadyInUseError("密码强度不足"); break; default: setAlreadyInUseError(userError.message); } } }, [userError]) const onSubmit = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault() setNotMatchedError(""); setAlreadyInUseError(""); if (signUpForm.password !== signUpForm.confirmPassword) { setNotMatchedError("两次输入的密码不一致"); return; // 密码不匹配时终止后续流程 } // 调用Firebase注册接口 createUserWithEmailAndPassword(signUpForm.email, signUpForm.password); // 注册成功后的处理(比如关闭模态框) if (user && !loading) { setAuthModalState({ open: false }); } } return ( <Flex direction="column" gap={4} p={4}> <Input type="email" value={signUpForm.email} onChange={(e) => setSignUpForm({...signUpForm, email: e.target.value})} placeholder="请输入邮箱" /> <Input type="password" value={signUpForm.password} onChange={(e) => setSignUpForm({...signUpForm, password: e.target.value})} placeholder="请输入密码" /> <Input type="password" value={signUpForm.confirmPassword} onChange={(e) => setSignUpForm({...signUpForm, confirmPassword: e.target.value})} placeholder="请确认密码" /> {notMatchedError && <Text color="red.500" fontSize="sm">{notMatchedError}</Text>} {alreadyInUseError && <Text color="red.500" fontSize="sm">{alreadyInUseError}</Text>} <Button isLoading={loading} colorScheme="blue" onClick={onSubmit}> 注册 </Button> </Flex> ) } export default SignUp;
关键修改说明
- 移除无用的
useSignInWithEmailAndPassword,直接通过注册接口完成流程 - 利用
react-firebase-hooks返回的userError状态自动捕获注册错误,无需手动处理Promise - 补充密码不匹配时的终止逻辑,避免无效调用
- 针对常见错误码做友好提示,提升用户体验
内容的提问来源于stack exchange,提问作者landingburn
相关产品推荐
相关产品推荐

