登录后history.push()无法跳转问题求助
history.push()不触发页面跳转的问题 我看了你的代码,问题核心在于App组件的认证状态没有在登录操作后及时更新,导致路由跳转逻辑没有触发。
问题根源
App里的useEffect依赖的是空数组[],这意味着它只会在组件首次挂载时执行一次。当你在Login组件里设置了authorization cookie并调用history.push('/')后,App组件的isAuthenticated状态还是初始的false——首页的Route依然会渲染Login组件,而不是触发Redirect到/home。只有手动刷新页面,App重新挂载时,useEffect才会再次检查cookie、更新状态,这时候才会完成跳转。
解决方案
我们需要让App组件能实时感知到认证状态的变化,这里提供几种可行方案,按推荐程度排序:
方案1:用Context管理全局认证状态(最推荐)
把认证状态和更新方法抽离到全局Context中,让Login组件可以直接触发状态更新,不用依赖cookie的被动读取。
- 先创建AuthContext文件:
// AuthContext.js import React, { createContext, useContext, useState, useEffect } from 'react'; import cookie from 'cookie'; const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [isAuthenticated, setAuthenticated] = useState(false); // 初始化检查cookie useEffect(() => { checkAuthStatus(); }, []); // 抽离检查认证状态的方法 const checkAuthStatus = () => { setAuthenticated(!!cookie.get('authorization')); }; // 登录成功后调用的方法 const handleLoginSuccess = () => { setAuthenticated(true); }; // 登出方法(可选) const handleLogout = () => { cookie.remove('authorization', { path: '/' }); setAuthenticated(false); }; return ( <AuthContext.Provider value={{ isAuthenticated, handleLoginSuccess, handleLogout }}> {children} </AuthContext.Provider> ); }; export const useAuth = () => useContext(AuthContext);
- 修改App组件,使用Context中的状态:
// App.js import { AuthProvider, useAuth } from './AuthContext'; import { Router, Switch, Route, Redirect } from 'react-router-dom'; function AppContent() { const { isAuthenticated } = useAuth(); return ( <Switch> <Route exact path="/"> {isAuthenticated ? <Redirect to="/home" /> : <Login />} </Route> <PrivateRoute exact path="/user/:id" component={UserDetail} auth={isAuthenticated} /> <PrivateRoute exact path="/createuser" component={CreateUser} auth={isAuthenticated} /> <PrivateRoute exact path="/home" component={ListUser} auth={isAuthenticated} /> </Switch> ); } function App() { return ( <AuthProvider> <Router> <AppContent /> </Router> </AuthProvider> ); } export default App;
- 修改Login组件,登录成功后更新全局状态:
// login.js import { useAuth } from './AuthContext'; import { useHistory } from 'react-router-dom'; function Login() { const history = useHistory(); const { handleLoginSuccess } = useAuth(); const loginUser = (body) => { SetLoader(true); fetch('/api/v2/users/tokens', { method: 'POST', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json', } }) .then(response => { SetLoader(false); if (response.status == 200) { SetError(false); cookie.set('authorization', response.headers.map.authorization, { path: '/' }); // 先更新全局认证状态 handleLoginSuccess(); // 再跳转(直接跳/home或/都可以,状态更新后路由逻辑会生效) history.push('/home'); } else { SetError(true); StoreResponse(JSON.parse(response._bodyInit).message); } }) .catch((error) => { console.error('Error:', error); }); } // 其余组件代码... } export default Login;
方案2:简化版 - 登录后直接跳转到/home
如果不想引入Context,也可以直接在登录成功后跳转到目标页面,绕过首页的Redirect逻辑:
// login.js 中的修改 if (response.status == 200) { SetError(false); cookie.set('authorization', response.headers.map.authorization, { path: '/' }); // 直接跳转到/home,跳过首页的判断 history.push('/home'); }
这个方案能快速解决跳转问题,但没有同步全局状态,后续如果有其他依赖isAuthenticated的逻辑可能会出现不一致,适合临时快速修复。
方案3:用react-cookie监听cookie变化(可选)
可以借助react-cookie库的useCookie钩子自动监听cookie变化,触发状态更新:
// App.js import { useCookie } from 'react-cookie'; function App() { const [authCookie] = useCookie('authorization'); const [isAuthenticated, setAuthenticated] = useState(false); // 当authCookie变化时自动更新状态 useEffect(() => { setAuthenticated(!!authCookie); }, [authCookie]); // 其余组件代码... }
这个方法不需要修改Login组件,但需要额外安装依赖,灵活性不如Context方案。
总结
核心问题就是认证状态没有在登录操作后同步更新,只要让App组件能及时感知到登录成功的事件,更新isAuthenticated状态,history.push()就能正常触发路由跳转逻辑了。
内容的提问来源于stack exchange,提问作者Sriharsha K

