React实现条件触发自动页面跳转(路由鉴权场景)问题求助
可行实现方案
核心问题说明
你用的是React Router v6版本,之前跳转不生效有四个直接原因:
- 旧版的
Redirect组件在v6中已经被移除,不能再使用 - 声明式跳转组件
Navigate必须放在组件return的渲染分支里才会生效,写在普通逻辑、事件回调里不会触发渲染,自然没有效果 - 事件回调里的跳转要使用v6提供的
useNavigate命令式API,只存储cookie不会触发路由切换 - 混用原生
document.cookie和引入的js-cookie库操作cookie,两者默认路径配置不一致,很容易出现存完cookie之后读不到值的问题
具体实现步骤
1. 实现未携带token访问首页自动跳转登录页
直接修改Home组件,引入Navigate组件,在组件渲染阶段判断token是否存在,不存在则直接返回重定向组件。
修改后的Home组件代码:
import React from 'react'; import '../styles/home.css' import { Navigate } from 'react-router-dom' import cookie from 'js-cookie' const Home = () => { const token = cookie.get('token') const userId = cookie.get('userId') // 无合法token直接重定向到登录页,replace替换历史记录避免回退死循环 if (!token || !userId) { return <Navigate to="/login" replace /> } return ( <> Home </> ); } export default Home;
2. 实现注册/登录成功后自动跳转首页
在Login、Register组件中引入useNavigate hook拿到跳转方法,接口请求成功、cookie存储完成后,调用跳转方法切到首页,同时统一用js-cookie的set方法存储cookie,和读取逻辑保持一致避免异常。
修改后的Register组件代码:
import React, {useState} from 'react'; import '../styles/register.css' import axios from 'axios' import { useNavigate } from 'react-router-dom' import cookie from 'js-cookie' const Register = () => { const [name, setName] = useState('') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const navigate = useNavigate() const registerUser = (e) => { e.preventDefault() axios.post('/api/user/register', { name: name, email: email, password: password }).then(res => { cookie.set('token', res.data.token) cookie.set('userId', res.data.userId) // 注册成功跳转首页,replace替换当前历史记录,避免用户点回退回到注册页 navigate('/', { replace: true }) }).catch(err => { alert(`Error registering!`) setName('') setEmail('') setPassword('') console.log(err) }) } return ( <> <form onSubmit={e => registerUser(e)}> <input type="text" placeholder="Enter your Name" value={name} onChange={e => setName(e.target.value)}/> <br/> <input type="email" placeholder="Enter your Email" required={true} value={email} onChange={e => setEmail(e.target.value)}/> <br/> <input type="password" placeholder="Enter your Password" required={true} value={password} onChange={e => setPassword(e.target.value)}/> <br/> <button type="submit">Register</button> </form> </> ); } export default Register;
修改后的Login组件逻辑和Register完全一致,替换对应接口地址、提示文案即可:
import React, {useState} from 'react'; import '../styles/register.css' import axios from 'axios' import { useNavigate } from 'react-router-dom' import cookie from 'js-cookie' const Login = () => { const [name, setName] = useState('') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const navigate = useNavigate() const loginUser = (e) => { e.preventDefault() axios.post('/api/user/login', { name: name, email: email, password: password }).then(res => { cookie.set('token', res.data.token) cookie.set('userId', res.data.userId) navigate('/', { replace: true }) }).catch(err => { alert(`Error logging in!`) setName('') setEmail('') setPassword('') console.log(err) }) } return ( <> <form onSubmit={e => loginUser(e)}> <input type="text" placeholder="Enter your Name" value={name} onChange={e => setName(e.target.value)}/> <br/> <input type="email" placeholder="Enter your Email" required={true} value={email} onChange={e => setEmail(e.target.value)}/> <br/> <input type="password" placeholder="Enter your Password" required={true} value={password} onChange={e => setPassword(e.target.value)}/> <br/> <button type="submit">Login</button> </form> </> ); } export default Login;
补充优化(可选)
如果后续路由增多,可以把鉴权逻辑抽成公共的ProtectedRoute组件,不用每个需要鉴权的页面都重复写token判断:
// 组件位置:./components/ProtectedRoute.jsx import { Navigate } from 'react-router-dom' import cookie from 'js-cookie' const ProtectedRoute = ({ children }) => { const token = cookie.get('token') if (!token) { return <Navigate to="/login" replace /> } return children } export default ProtectedRoute
抽完之后入口文件的路由可以改成下面的写法,后续新增受保护路由直接套这个组件即可:
// 修改Index.jsx中的Routes部分 <Routes> <Route path='/' element={ <ProtectedRoute> <Home /> </ProtectedRoute> } /> <Route path='/login' element={<Login/>}/> <Route path='/register' element={<Register/>}/> </Routes>
抽离后Home组件里就不用再单独写token判断逻辑,维护成本更低。
内容的提问来源于stack exchange,提问作者Andy
相关产品推荐
相关产品推荐

