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

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');
});
解决方案

问题根源

  1. <Navigate>组件使用方式错误:在axios回调或useEffect的Promise回调中返回<Navigate>组件无效,因为这些代码不在React组件的渲染流程里,React不会处理这里返回的JSX元素。
  2. 登录逻辑判断错误:后端登录成功时返回的是{success: true, message: 'Login successful'},但前端代码里判断的是if (response.data.message),这会导致登录成功时进入显示提示的分支,重定向代码所在的else分支永远不会执行。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:54:58