React项目登录按钮点击无响应问题求助(对接MongoDB)
React登录按钮无反应问题排查与修复
问题描述
我是React新手,已为对接MongoDB的React Web应用搭建认证系统,注册功能可正常使用,但使用已注册的用户信息点击登录按钮时无任何反应。相关代码如下:
RequireAuth.jsx
import { Navigate } from "react-router-dom"; import { useAuth } from './auth'; function getToken() { return localStorage.getItem('token'); } function getInternalData() { return JSON.parse(localStorage.getItem('internalData')); } export const RequireAuth = ({ children }) => { const auth = useAuth(); if (!getToken()) { return <Navigate to="/login" />; } return children; }; export const RequireLogOut = ({ children }) => { const auth = useAuth(); if (getToken()) { return <Navigate to="/home" />; } return children; }; export { getToken, getInternalData };
auth.jsx
import {useState, useContext, createContext } from "react"; const AuthContext = createContext(null); export const AuthProvider = ({children }) => { const [token, setToken] = useState(""); const login = (token, internalData) => { console.log(token); localStorage.setItem('token', JSON.stringify(token)); localStorage.setItem('internalData', JSON.stringify(internalData)); setToken(token); }; const logout = () => { localStorage.removeItem('token'); localStorage.removeItem('internalData'); setToken(""); } return <AuthContext.Provider value={{token, login, logout}}>{children}</AuthContext.Provider> }; export const useAuth = () => { return useContext(AuthContext); };
login.jsx
import { useState } from 'react'; import { useNavigate, Link } from 'react-router-dom' import { useAuth } from './auth'; import axios from 'axios' import { LockClosedIcon } from '@heroicons/react/24/solid' import { RequireAuth, RequireLogOut } from "./RequireAuth"; async function loginUser(credentials) { return fetch('http://localhost:4000/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }) .then(data => data.json()) } export default function LoginForm() { const [loginValues, setLoginValues] = useState({ email: "", password: "" }); const navigate = useNavigate() const [error, setError] = useState(""); const auth = useAuth(); const handleChange = (e) => { const { name, value } = e.target; const newValues = { ...loginValues, [name]: value }; console.log(newValues); setLoginValues(newValues); }; const handleSubmit = async e => { e.preventDefault(); //const token = await loginUser(loginValues); const tokenData = await axios.post('http://localhost:4000/login/', loginValues); console.log(tokenData.data) if (tokenData.data.success) { setError(""); auth.login(tokenData.data.token, tokenData.data.internalData); } else { setError("Credentials are incorrect. Try again"); } } return ( <> <div className="min-h-full flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8"> <div className="max-w-md w-full space-y-8"> <div> <img className="mx-auto h-36 w-auto" src="/images/logo.png" alt="Workflow" /> <h2 className="mt-6 text-center text-3xl tracking-tight font-bold text-gray-900"> Sign in to your account </h2> <p className="mt-2 text-center text-sm text-gray-600"> Or{' '} <a href="http://localhost:3000/register" className="font-medium text-gameblue hover:text-gamebluehover"> don't have an account yet? </a> </p> </div> {error ? <div>{error}</div> : ""} <form onSubmit={handleSubmit} className="mt-8 space-y-6" action="#" method="POST"> <input type="hidden" name="remember" defaultValue="true" /> <div className="rounded-md shadow-sm -space-y-px"> <div> <label htmlFor="email-address" className="sr-only"> Email address </label> <input onChange={handleChange} value={loginValues.email} id="email-address" name="email" type="email" autoComplete="email" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-gameblue focus:z-10 sm:text-sm" placeholder="Email address" /> </div> <div> <label htmlFor="password" className="sr-only"> Password </label> <input onChange={handleChange} value={loginValues.password} id="password" name="password" type="password" autoComplete="current-password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-gameblue focus:z-10 sm:text-sm" placeholder="Password" /> </div> </div> <div className="flex items-center justify-between"> <div className="flex items-center"> <input id="remember-me" name="remember-me" type="checkbox" className="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" /> <label htmlFor="remember-me" className="ml-2 block text-sm text-gray-900"> Remember me </label> </div> <div className="text-sm"> <a href="#" className="font-medium text-gameblue hover:text-gamebluehover"> Forgot your password? </a> </div> </div> <div> <button type="submit" className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-gameblue hover:bg-gamebluehover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" > <span className="absolute left-0 inset-y-0 flex items-center pl-3"> <LockClosedIcon className="h-5 w-5 text-gamebluelight group-hover:text-gamebluelightest" aria-hidden="true" /> </span> Sign in </button> </div> </form> </div> </div> </> ); }
问题排查与修复
1. 未处理Axios请求错误
handleSubmit函数中使用await axios.post但未捕获异常,若后端接口无响应、出现跨域错误或其他网络问题,会导致函数中断执行,按钮点击后无任何反馈。
修复代码:
const handleSubmit = async e => { e.preventDefault(); try { const tokenData = await axios.post('http://localhost:4000/login/', loginValues); console.log(tokenData.data) if (tokenData.data.success) { setError(""); auth.login(tokenData.data.token, tokenData.data.internalData); navigate('/home'); // 新增页面跳转逻辑 } else { setError("Credentials are incorrect. Try again"); } } catch (err) { console.error('登录请求失败:', err); setError('登录失败,请检查网络或后端服务状态'); } }
2. 登录成功后未跳转页面
登录成功调用auth.login后,没有触发页面跳转,用户看不到状态变化,误以为登录无反应。
修复:在auth.login后添加navigate('/home')(已包含在上述修复代码中)。
3. Token存储冗余JSON.stringify
auth.jsx中login函数对token执行JSON.stringify,若后端返回的token本身是字符串,会导致localStorage中存储的是带引号的字符串,后续getToken获取的值可能不符合预期,影响认证逻辑。
修复代码:
const login = (token, internalData) => { console.log(token); localStorage.setItem('token', token); // 移除冗余的JSON.stringify localStorage.setItem('internalData', JSON.stringify(internalData)); setToken(token); };
4. RequireAuth依赖localStorage而非AuthContext
RequireAuth组件直接从localStorage获取token,而非使用AuthContext中的状态,可能导致状态不同步(比如登录后AuthContext的token更新,但组件未重新渲染)。
修复代码:
export const RequireAuth = ({ children }) => { const { token } = useAuth(); if (!token) { return <Navigate to="/login" />; } return children; }; export const RequireLogOut = ({ children }) => { const { token } = useAuth(); if (token) { return <Navigate to="/home" />; } return children; };
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

