React登录成功后无法重定向问题求助
问题
登录成功后需要自动跳转到指定页面,但当前代码仅在表单底部显示成功提示弹窗,使用react-router-dom的<Navigate>组件无法实现重定向。会话已正常建立,但重定向功能失效。相关代码如下:
JSX 文件
import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { Navigate } from 'react-router-dom'; const Login = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loginStatus, setLoginStatus] = useState(''); axios.defaults.withCredentials = true; const login = (event) => { event.preventDefault(); axios .post('http://localhost:5000/login', { username: username, password: password, }) .then((response) => { if (response.data.message) { setLoginStatus(response.data.message); } else { setLoginStatus(response.data.username); return <Navigate to="/admin/home" />; } }) .catch((error) => { console.error('Error logging in:', error); }); }; useEffect(() => { axios .get('http://localhost:5000/check-session') .then((response) => { if (response.data.loggedIn) { return <Navigate to="/admin/home" />; // Redirect to /admin/home if already logged in } }) .catch((error) => { console.error('Error checking session:', error); }); }, []); return ( <div className='Login-page'> <h1>Login</h1> <form onSubmit={login}> <button type='submit' className='btn btn-outline-primary'> Login </button> </form> {loginStatus && <p>{loginStatus}</p>} </div> ); }; export default Login;
Server.js (Express 文件)
const express = require('express'); const app = express(); const mysql = require('mysql'); const morgan = require('morgan'); const cors = require('cors'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); // Middleware app.use(cors({ origin: 'http://localhost:3000', // Replace with your frontend application's URL methods: ["GET","POST","PUT", "DELETE"], credentials: true, // Allow credentials (cookies) })); app.use(cookieParser()); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.json()); // Parse JSON bodies app.use(express.urlencoded({ extended: true })); // Parse URL-encoded bodies app.use(morgan('dev')); // Use Morgan for logging HTTP requests // Session setup /* Set Cookie Settings */ app.use( session({ secret: 'secretKey123', resave: false, saveUninitialized: false, cookie: { secure: false, // Set this to true if you use HTTPS maxAge: 24 * 60 * 60 * 1000, // 24 hours }, }) ); // Routes app.post('/login', (req, res) => { const username = req.body.username; const password = req.body.password; connection.query( 'SELECT * FROM admin_users WHERE username = ? AND password = ?', [username, password], (error, results, fields) => { if (error) { console.error('Error executing MySQL query: ' + error.stack); return res.status(500).json({ error: 'Internal Server Error' }); } if (results.length > 0) { req.session.username = username; // Set session variable to the username res.json({ success: true, message: 'Login successful' }); } else { res.json({ success: false, message: 'Invalid username or password' }); } } ); }); app.get('/check-session', (req, res) => { if (req.session.username) { res.json({ loggedIn: true, user: req.session.username }); } else { res.json({ loggedIn: false }); } }); app.post('/check-session', (req, res) => { console.log(req.session) if (req.session.isLoggedIn) { res.json({ isLoggedIn: true }); } else { res.json({ isLoggedIn: false }); } }); app.post('/logout', (req, res) => { req.session.destroy((error) => { if (error) { console.error('Error destroying session:', error); return res.status(500).json({ error: 'Internal Server Error' }); } res.clearCookie('userId'); // Clear the session cookie res.json({ success: true, message: 'Logout successful' }); }); }); // Start the server app.listen(5000, () => { console.log('Server started on port 5000'); });
解决方案
问题根源
<Navigate>组件使用方式错误:在axios回调或useEffect的Promise回调中返回<Navigate>组件无效,因为这些代码不在React组件的渲染流程里,React不会处理这里返回的JSX元素。- 登录逻辑判断错误:后端登录成功时返回的是
{success: true, message: 'Login successful'},但前端代码里判断的是if (response.data.message),这会导致登录成功时进入显示提示的分支,重定向代码所在的else分支永远不会执行。 useEffect中重定向逻辑无效:同样是在Promise回调里返回<Navigate>,React无法识别。
修复步骤
方案1:使用useNavigate钩子(推荐)
react-router-dom提供的useNavigate钩子可以直接在函数内部触发跳转,更适合异步回调场景。
修改后的Login组件代码:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { useNavigate } from 'react-router-dom'; // 替换Navigate为useNavigate const Login = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loginStatus, setLoginStatus] = useState(''); const navigate = useNavigate(); // 初始化navigate函数 axios.defaults.withCredentials = true; const login = (event) => { event.preventDefault(); axios .post('http://localhost:5000/login', { username: username, password: password, }) .then((response) => { if (response.data.success) { // 登录成功,直接跳转 navigate('/admin/home'); } else { // 登录失败,显示错误提示 setLoginStatus(response.data.message); } }) .catch((error) => { console.error('Error logging in:', error); setLoginStatus('登录失败,请重试'); }); }; useEffect(() => { axios .get('http://localhost:5000/check-session') .then((response) => { if (response.data.loggedIn) { // 已登录,直接跳转 navigate('/admin/home'); } }) .catch((error) => { console.error('Error checking session:', error); }); }, [navigate]); // 添加navigate到依赖数组 return ( <div className='Login-page'> <h1>Login</h1> <form onSubmit={login}> {/* 补充原代码遗漏的用户名和密码输入框 */} <div> <label>用户名:</label> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} required /> </div> <div> <label>密码:</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> <button type='submit' className='btn btn-outline-primary'> Login </button> </form> {loginStatus && <p>{loginStatus}</p>} </div> ); }; export default Login;
方案2:使用状态变量控制重定向
如果坚持使用<Navigate>组件,可以通过状态变量控制是否在组件渲染时输出该组件:
修改后的Login组件关键部分:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { Navigate } from 'react-router-dom'; const Login = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [loginStatus, setLoginStatus] = useState(''); const [shouldRedirect, setShouldRedirect] = useState(false); // 新增重定向状态 // ... 其他代码 const login = (event) => { event.preventDefault(); axios .post('http://localhost:5000/login', { username: username, password: password, }) .then((response) => { if (response.data.success) { setShouldRedirect(true); // 设置重定向状态 } else { setLoginStatus(response.data.message); } }) .catch((error) => { console.error('Error logging in:', error); }); }; useEffect(() => { axios .get('http://localhost:5000/check-session') .then((response) => { if (response.data.loggedIn) { setShouldRedirect(true); // 设置重定向状态 } }) .catch((error) => { console.error('Error checking session:', error); }); }, []); // 优先判断重定向,符合条件则直接渲染Navigate组件 if (shouldRedirect) { return <Navigate to="/admin/home" />; } return ( // ... 原渲染内容 ); };
额外注意事项
- 原代码的登录表单遗漏了用户名和密码输入框,已在修复代码中补充,否则无法提交登录信息。
- 后端
POST /check-session接口判断的是req.session.isLoggedIn,但登录时仅设置了req.session.username,逻辑不一致,建议统一使用req.session.username判断登录状态,避免后续问题。
内容的提问来源于stack exchange,提问作者Jeremiah Rodriguez
相关产品推荐
相关产品推荐

