React受保护路由致登出后无法跳转Home组件的问题修复
问题修复方案
核心问题分析
登出后地址栏跳转但Grid组件空白,根源是ProtectedRoute组件未响应localStorage中token的变化。原代码里localStorage.getItem('token')仅在组件初始化时执行一次,删除token后组件不会重新渲染,仍返回Grid的路由;但此时Grid因无token加载失败,呈现空白。手动刷新时组件重新初始化,才会检测到token缺失并跳转到Home。
修复步骤
1. 让ProtectedRoute响应token变化
修改ProtectedRoute.js,通过useState和useEffect监听localStorage变化,确保token删除后组件能重新判断权限:
import React, { useState, useEffect } from 'react' import { Redirect, Route } from 'react-router-dom' const ProtectedRoute = (props) => { const [user, setUser] = useState(localStorage.getItem('token')); useEffect(() => { const handleStorageUpdate = () => { setUser(localStorage.getItem('token')); }; window.addEventListener('storage', handleStorageUpdate); return () => window.removeEventListener('storage', handleStorageUpdate); }, []); if(!user) { return <Redirect to="/" />; } return <Route {...props} />; }; export default ProtectedRoute;
2. 修正Navbar中的代码问题
原Navbar存在useHistory()调用位置错误、token未实时获取的问题,修改如下:
import { useHistory } from "react-router-dom"; import axios from 'axios'; const Navbar = () => { const history = useHistory(); // 必须在函数组件内部调用useHistory const logout = () => { const authToken = localStorage.getItem('token'); // 实时获取当前token const headers = { "Accept": 'application/json', "Authorization": `Bearer ${authToken}` }; axios.post('http://127.0.0.1:8000/api/logout', {}, {headers}) // 传空对象符合接口规范 .then(resp => { localStorage.removeItem('token'); history.push('/'); }).catch(err => { console.log(err); }); } return <Button onClick={logout}>Logout</Button>; } export default Navbar;
可选优化:统一管理token状态(推荐)
若项目规模较大,建议在App组件中管理token状态,通过props传递给ProtectedRoute,让路由判断更可靠:
修改App.js:
import { useState, useEffect } from 'react'; import { Router, Switch, Route } from 'react-router-dom'; import ProtectedRoute from './ProtectedRoute'; import Home from './Home'; import Grid from './Grid'; const App = () => { const [token, setToken] = useState(localStorage.getItem('token')); useEffect(() => { const handleStorageChange = () => { setToken(localStorage.getItem('token')); }; window.addEventListener('storage', handleStorageChange); return () => window.removeEventListener('storage', handleStorageChange); }, []); return ( <> <Router> <Switch> <Route exact path="/" component={Home} /> <ProtectedRoute token={token} path="/gallery" component={Grid} /> </Switch> </Router> </> ); } export default App;
修改ProtectedRoute.js:
import React from 'react' import { Redirect, Route } from 'react-router-dom' const ProtectedRoute = ({ token, ...props }) => { if(!token) { return <Redirect to="/" />; } return <Route {...props} />; }; export default ProtectedRoute;
内容的提问来源于stack exchange,提问作者sp92
相关产品推荐
相关产品推荐

