React实现登录功能时react-router-dom路由跳转不符合预期如何解决
React登录路由逻辑修正方案
核心问题梳理
- App.js未定义
/login路由,你写的重定向目标不存在 - 登录状态判断逻辑完全颠倒:未登录状态反而渲染登录页,登录后才应该跳转到业务页面
isLog状态初始值为undefined,首次加载时判断逻辑失效- Login组件按钮同时绑定了表单提交事件和独立点击跳转事件,逻辑冲突,且propTypes类型定义错误(
isLogIn是父组件传入的函数,不是布尔值) hideMenu判断逻辑错误,登录页不需要展示侧边栏和头部,你写的是仅在根路径显示菜单,和需求相反- 所有业务页面(/health、/useradmin)未加登录校验,用户直接输入地址即可绕过登录访问
修正后代码
App.js
import React, { useEffect, useState } from 'react'; import { BrowserRouter as Router, Redirect, Route, Switch, } from 'react-router-dom'; import Header from './components/Header/Header'; import Health from './components/Health/Health'; import Login from './components/Login/Login'; import NotFound from './components/NotFound/NotFound'; import SidebarNav from './components/SidebarNav/SidebarNav'; import UserAdmin from './components/UserAdmin/UserAdmin'; // 封装受保护路由:未登录自动跳转登录页 const ProtectedRoute = ({ component: Component, isLog, ...rest }) => { return ( <Route {...rest} render={props => isLog ? ( <Component {...props} /> ) : ( <Redirect to="/login" /> ) } /> ) } const App = () => { const [hideMenu, setHideMenu] = useState(false); // 登录状态默认未登录 const [isLog, setIsLog] = useState(false); useEffect(() => { // 只有登录页隐藏菜单,其他页面展示菜单 setHideMenu(window.location.pathname === '/login'); }, [window.location.pathname]); const handleLogin = (isLog) => { setIsLog(isLog); // 可选:登录状态可以存到localStorage,刷新页面不用重新登录 localStorage.setItem('isLog', isLog) }; // 页面刷新时从本地存储恢复登录状态 useEffect(() => { const savedLoginState = localStorage.getItem('isLog') === 'true' setIsLog(savedLoginState) }, []) return ( <React.Fragment> <Router> {!hideMenu && ( <React.Fragment> <SidebarNav /> <Header /> </React.Fragment> )} <div className={hideMenu ? '' : 'content'}> <main> <Switch> {/* 登录页路由 */} <Route exact path="/login"> {isLog ? <Redirect to="/health" /> : <Login isLogIn={handleLogin} />} </Route> {/* 根路径自动跳转:登录了去健康页,没登录去登录页 */} <Route exact path="/"> <Redirect to={isLog ? "/health" : "/login"} /> </Route> {/* 受保护的业务路由,必须登录才能访问 */} <ProtectedRoute path="/health" exact component={Health} isLog={isLog} /> <ProtectedRoute path="/useradmin" exact component={UserAdmin} isLog={isLog} /> <Route path="*" component={NotFound} /> </Switch> </main> </div> </Router> </React.Fragment> ); }; export default App;
Login.jsx
import './Login.css'; import { PropTypes } from 'prop-types'; import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; const Login = (props) => { let history = useHistory(); // 给受控组件加初始空值,避免报错 const [email, setEmail] = useState(''); const [pwd, setPwd] = useState(''); const handleSubmit = (e) => { e.preventDefault(); // 这里可以加实际的账号密码校验逻辑 props.isLogIn(true); // 登录状态更新后跳转 history.push('/health'); }; Login.propTypes = { // 传入的isLogIn是函数,类型定义修正 isLogIn: PropTypes.func.isRequired, }; return ( <div className="div-login"> <div> <form onSubmit={handleSubmit}> <input type="email" value={email} placeholder="email..." required onChange={(e) => setEmail(e.target.value)} /> <input type="password" value={pwd} placeholder="password..." required onChange={(e) => setPwd(e.target.value)} /> {/* 去掉按钮单独的onClick跳转,走表单提交逻辑 */} <button type="submit"> Log In </button> </form> </div> </div> ); }; export default Login;
效果说明
- 用户首次打开站点自动跳转
/login登录页,无侧边栏和头部 - 输入账号密码点击登录后,自动跳转
/health页面,展示侧边栏和头部 - 未登录状态直接输入
/health、/useradmin地址,自动跳转回登录页 - 登录状态刷新页面不需要重新登录(localStorage存储逻辑可根据需要删除)
内容的提问来源于stack exchange,提问作者Leo Garry
相关产品推荐
相关产品推荐

