React登录组件需三次点击才跳转问题(Node.js+Express+MySQL)
登录系统前两次点击失败、第三次才跳转的问题修复方案
核心问题分析
- 前端请求时序错误:POST请求还未完成后端验证,就提前触发GET请求获取状态,导致拿到的是旧状态。
- React状态更新特性误用:刚调用
setAuth就用auth变量判断,此时auth还是更新前的旧值。 - 后端全局变量设计错误:用全局
auth存储验证状态,多请求下状态会混乱,且POST请求未直接返回验证结果,依赖后续GET请求的逻辑完全不合理。 - 数据库查询结果判断错误:用
result != null判断是否匹配用户,实际上无匹配时result是空数组而非null。
前端Signin.js修改方案
import React, { useState } from 'react'; import Navbar from './Navbar'; import './signin.css'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; function Signin() { const [userId, setUserId] = useState(""); const [password, setPassword] = useState(""); const [accessCode, setAccessCode] = useState(""); const navigate = useNavigate(); const signInInfoSent = async () => { try { const response = await axios.post("http://localhost:3001/api/get/signin", { userId: userId, password: password }); if (response.data.success) { navigate("/Dashhome"); } else { alert('Incorrect Login/Password'); } } catch (error) { console.error("登录请求失败:", error); alert('登录请求出错,请稍后重试'); } }; return ( <> <Navbar /> <div id="signUp"> <div id="form"> <label htmlFor="userId">User ID</label> <input type="text" id="userId" placeholder="Username" onChange={(e) => setUserId(e.target.value)} /> <label htmlFor="password">Password</label> <input type="password" id="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} /> <label htmlFor="otp">Access Code</label> <input type="text" id="otp" placeholder="OTP" onChange={(e) => setAccessCode(e.target.value)} /> <button onClick={signInInfoSent}>Sign in</button> </div> </div> </> ); } export default Signin;
前端修改说明
- 移除多余的
receiveauthentication函数,直接在POST请求响应中处理登录结果,解决时序问题。 - 改用
useNavigate进行路由跳转,替代原生document.location.href,符合React Router规范。 - 用
async/await处理异步请求,代码更清晰,同时增加错误捕获逻辑。 - 修正输入框
type属性为标准的text(原textbox非HTML标准类型)。
后端index.js修改方案
const express = require('express') const app = express() const mySql = require('mysql'); const cors = require('cors') const bodyParser = require('body-parser') const db = mySql.createPool({ host:"127.0.0.1", user:"root", password:"password", database:"kotekdatabase" }) app.use(bodyParser.urlencoded({extended: true})) app.use(express.json()) app.use(cors()) let userIdG; var trade_data = {}; app.post("/api/get/signin", (req,res)=>{ const userid = req.body.userId; userIdG = userid; const password = req.body.password; const sqlSelect = `SELECT * FROM signup WHERE userid = ? AND password = ?`; db.query(sqlSelect,[userid , password], (err, result)=> { if(err){ console.error("数据库查询错误:", err); return res.status(500).json({success: false, message: "服务器内部错误"}); } if(result.length > 0) { console.log("登录成功:", userid); res.json({success: true}); } else { console.log("登录失败: 用户名或密码错误"); res.json({success: false}); } }) }) // 保留其他现有接口(如retrieveStrategies等) app.listen(3001, () => { console.log("running on port 3001"); })
后端修改说明
- 移除全局变量
auth:直接在POST请求的数据库查询回调中返回验证结果,避免全局状态共享的混乱。 - 修正查询结果判断逻辑:用
result.length > 0判断是否存在匹配用户,替代错误的result != null。 - 增加错误处理:捕获数据库查询错误,返回500状态码和错误信息,避免请求挂起。
- 直接返回JSON结果:前端可直接通过响应体获取验证状态,无需额外发送GET请求。
额外优化建议
- 后端
userIdG全局变量存在多用户并发问题,建议改用Session或JWT令牌存储用户身份信息,避免用户信息互相覆盖。 - 目前登录逻辑未使用Access Code(OTP),建议补充OTP验证步骤提升安全性。
- 数据库中不要明文存储密码,用bcrypt等加密算法哈希后再存储。
内容的提问来源于stack exchange,提问作者Adam Saleem
相关产品推荐
相关产品推荐

