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

React登录请求返回数据后页面被覆盖无数据的问题求助

React登录请求后页面被覆盖问题解决

问题描述

我正在学习React,遇到了一个异常问题:

  • 当发送无数据的API请求(故意未预先处理异常)时,响应能正常返回并显示预期异常;
  • 但发送带邮箱、密码的登录请求时,API返回数据后页面会立刻被覆盖,无法理解为何会触发新请求。

代码片段

sendLogin函数

async function sendLogin(userLoginModel: LoginModelView) {
    let data = userLoginModel;

    await fetch(i.login.url, {
      method: i.login.methodType,
      body: JSON.stringify(data),
      headers: {
        "Content-Type": "application/json",
      },
    })
      .then((response) => {
        var prom;
        if (response.ok) {
          prom = response.json() as Promise<ResultModel<UserModel>>;
          prom.then((result) => {
            setUser(result.data);
            handOverAlert(
              new AlertModel({
                message: result.message,
                isSuccess: result.isSuccess,
              })
            );
          });
        } else {
          prom = response.json() as Promise<ResultModel<boolean>>;
          prom.then((result) => {
            setUser(new UserModel());
            handOverAlert(
              new AlertModel({
                message: result.message,
                isSuccess: result.isSuccess,
              })
            );
          });
        }
      })
      .catch((error) => console.log(error));
  }

Login组件

export default function Login() {

 const [login, setLogin] = useState<LoginModelView>({email:"", password:""});
 const { sendLogin } = useAuth()

 function handelChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
     const {name, value} = e.target;
     setLogin(prevlogin => ({
         ...prevlogin,
         [name]:value
     }))
 }

 function send() {
    sendLogin(login)   // 调用API的函数
 }

 return (
     <Container component="main" maxWidth="xs">
        
         <CssBaseline />
         <Paper 
             sx={{
                 marginTop: "3%",
                 display: 'flex',
                 flexDirection: 'column',
                 alignItems: 'center',
             }}
             >
             <Avatar 
                 sx={{
                     margin: "1%",
                     backgroundColor: "red",
                 }}>
                 <LockIcon />
             </Avatar>
             <Typography component="h1" variant="h5">
                 Přihlášení
             </Typography>
             <form>
             <FormControl 
                 sx={{
                     width:"100%",
                     marginTop: "1%"
                 }}>
                 <TextField
                     variant="outlined"
                     margin="normal"
                     required
                     fullWidth
                     id="email"
                     label="Email"
                     autoComplete="email"
                     autoFocus
                     name="email"
                     value={login.email}
                     onChange={e => handelChange(e)}
                 />
                 <TextField
                     variant="outlined"
                     margin="normal"
                     required
                     fullWidth
                     name="password"
                     label="Heslo"
                     type="password"
                     id="password"
                     autoComplete="current-password"
                     value={login.password}
                     onChange={e => handelChange(e)}
                 />

                 <Button
                     sx={{
                         margin: "1%"
                     }}
                     type="submit"
                     fullWidth
                     variant="contained"
                     color="primary"
                     onClick={send}
                     
                 >
                     Přihlásit
                 </Button>
                 <Grid container>
                     <Grid item xs>
                         <Link href="/ForgotPassword" variant="body2">
                             Zapomenuté heslo?
                         </Link>
                     </Grid>
                     <Grid item xs>
                         <Link href="/Register" variant="body2">
                             {"Nejste registrováni? Registrujte se"}
                         </Link>
                     </Grid>
                 </Grid>
             </FormControl>
             </form>
         </Paper>
     </Container>
 );
}

问题原因及解决方法

核心原因

页面被覆盖是因为表单的默认提交行为:你的按钮type="submit",点击后会触发<form>标签的默认提交动作,导致浏览器刷新页面,覆盖之前的API响应状态。

解决方法(任选其一)

方法1:阻止表单默认提交行为

修改send函数,接收事件参数并调用preventDefault():

function send(e: React.FormEvent) {
  e.preventDefault(); // 阻止表单默认提交
  sendLogin(login);
}

方法2:修改按钮类型为button

将按钮的type从submit改为button,避免触发表单提交:

<Button
  sx={{ margin: "1%" }}
  type="button" // 改为button类型
  fullWidth
  variant="contained"
  color="primary"
  onClick={send}
>
  Přihlásit
</Button>

方法3:绑定表单的onSubmit事件

在<form>标签上绑定onSubmit事件,处理提交逻辑并阻止默认行为:

<form onSubmit={(e) => {
  e.preventDefault();
  sendLogin(login);
}}>

额外优化:统一async/await风格

你的sendLogin函数混用了async/await和.then(),建议统一使用async/await让代码更简洁易读:

async function sendLogin(userLoginModel: LoginModelView) {
  try {
    const response = await fetch(i.login.url, {
      method: i.login.methodType,
      body: JSON.stringify(userLoginModel),
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (response.ok) {
      const result = await response.json() as ResultModel<UserModel>;
      setUser(result.data);
      handOverAlert(new AlertModel({
        message: result.message,
        isSuccess: result.isSuccess,
      }));
    } else {
      const result = await response.json() as ResultModel<boolean>;
      setUser(new UserModel());
      handOverAlert(new AlertModel({
        message: result.message,
        isSuccess: result.isSuccess,
      }));
    }
  } catch (error) {
    console.log(error);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 00:24:18