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

如何在React中同步调用Axios?解决MongoDB用户重复注册问题

解决React中Axios异步验证导致重复注册的问题

你的问题核心在于**validateRegister是同步函数,但里面的用户存在性校验是异步的Axios请求**——函数会在请求还没拿到响应时就返回初始的errors对象,导致后续注册逻辑误以为没有重复用户,直接执行了注册操作。下面是具体的解决方案和修改后的代码:

步骤1:将验证函数改为异步函数

把validateRegister改成async函数,用await等待Axios请求完成,确保拿到结果后再返回完整的错误信息:

const validateRegister = async (values) => {
  let errors = {};
  const patternName = new RegExp('^[a-zA-Z ]{3,20}$')
  const patternPhone = new RegExp('^[0-9]{9,10}$')
  const patternEmail = new RegExp('^[a-zA-Z0-9._:$!%-]+@[a-zA-Z0-9.-]+.[a-zA-Z]$')
  const patternPassword = new RegExp('(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^A-Za-z0-9])(?=.{8,})')

  // 先完成同步格式校验
  if(!values.name || !patternName.test(values.name)){
    errors.name="Please enter a valid name"
  }
  if(!values.phone || !patternPhone.test(values.phone)){
    errors.phone="Please enter a valid Phone number of 9-10 digits"
  }
  if(!values.email || !patternEmail.test(values.email)){
    errors.email="Please enter a valid email address"
  }
  if(!values.password || !patternPassword.test(values.password)){
    errors.password="Please enter a strong password to continue. A strong password has: Atleast 8 characters in length, 2 letters in upper case, 1 special character (!@#$&*), 2 number (0-9), 3 letters in lower case"
  }
  if(!values.isTermsAndConditionsAccepted){
    errors.isTermsAndConditionsAccepted = "Please Accept the Terms and conditions"
  }

  // 如果格式校验已有错误,直接返回,无需查询数据库
  if (Object.keys(errors).length > 0) {
    return errors;
  }

  // 异步校验用户是否存在
  if(values.phone){
    let formData = new FormData();
    formData.append('phone', values.phone);
    console.log('inside user check')
    try {
      // 等待请求响应完成
      await axios.post('http://localhost:3001/doesUserExistByPhone', formData);
      // 请求成功说明用户不存在,无需添加错误
    } catch (errorResponse) {
      console.log(errorResponse)
      if(errorResponse.response.status===409){
        console.log('User already exist');
        errors.phone="User Already exist. If you've already registered. Please try to Login.";
      } else if(errorResponse.response.status===500){
        errors.phone = "Unable to register user, contact SwapiFi Support";
      }
    }
  }
  console.log('Errors found before creating user: ', errors);
  return errors;
}
export default validateRegister

步骤2:修改调用验证函数的逻辑

在useFormRegister里,因为validateRegister现在是异步函数,所以handleRegisterEvent要改成async函数,用await获取验证结果后再设置errors:

const useFormRegister = (submitForm) => {
  const [errors, setErrors] = useState({});
  const [dataIsCorrect, setDataIsCorrect] = useState(false);
  const [values, setValues] = useState({
    name: "",
    phone: "",
    email: "",
    password: "",
    isTermsAndConditionsAccepted: false
  })
  const [isLoading, setIsLoading] = useState(false); // 新增loading状态,防止重复点击

  const handleValueChangeEvent = (event) => {
    setValues({
      ...values,
      [event.target.name] : event.target.value,
    })
  }

  const handleRegisterEvent = async (event) => {
    console.log('Register button clicked');
    event.preventDefault();
    setIsLoading(true); // 开始验证时锁定按钮
    // 等待验证完成,拿到完整错误信息
    const validationErrors = await validateRegister(values);
    setErrors(validationErrors);
    setIsLoading(false); // 验证完成后解锁按钮
    setDataIsCorrect(true);
  }

  useEffect(() => {
    console.log('No. of errors:', Object.keys(errors).length)
    Object.entries(errors).map(([key, value]) => (
      console.log("Error, ", key, ':', value)
    ))
    if(Object.keys(errors).length === 0 && dataIsCorrect){
      submitForm(true);
      let formData = new FormData();
      Object.entries(values).map(([key, value]) => (
        formData.append(key, value)
      ))
      console.log(formData)
      axios.post('http://localhost:3001/registerUser', formData)
        .then(response => {console.log(response)})
        .catch(error=>{console.log(error)})
      // 注册完成后重置状态
      setDataIsCorrect(false);
    }
  }, [errors, dataIsCorrect, values, submitForm])

  return {handleValueChangeEvent, handleRegisterEvent, values, errors, isLoading};
}
export default useFormRegister

额外注意事项

  1. 后端必须重复校验:前端校验只是提升用户体验,恶意用户可以绕过前端直接调用后端接口,所以registerUser接口必须再次检查用户是否存在,返回409错误。
  2. 利用loading状态防重复提交:上面的代码新增了isLoading状态,在验证和注册过程中可以禁用注册按钮,避免用户重复点击导致多次请求。
  3. 确认后端状态码逻辑:要确保doesUserExistByPhone接口的状态码逻辑正确——比如用户存在时返回409,不存在时返回200,这样前端的try/catch才能正确处理。

内容的提问来源于stack exchange,提问作者ChivalrousRoot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 14:07:56