React Router+Redux私有路由问题:登录后无法跳转及获取用户信息
问题分析与解决方案
你的问题核心在于登录状态更新后,没有自动从登录页跳转到私有路由,具体原因拆解如下:
- 初始加载时,
fetchUser是异步请求,signIn初始值为false,根路由/会重定向到/login; - 当
fetchUser请求完成,signIn变为true,App组件重新渲染,但此时浏览器路径已经是/login,根路由的exact path="/"不再匹配,所以不会触发重定向到/dashboard; - 你的
PrivateRoute只有在用户主动访问/dashboard时才会执行登录检查,所以登录状态更新后不会自动跳转。
下面给出两种简单可行的解决方案:
方案一:在Login组件中监听登录状态
修改Login组件,让它连接Redux并监听signedIn状态,一旦检测到用户已登录,就自动跳转到仪表盘:
import { connect } from 'react-redux'; import { Redirect } from 'react-router-dom'; class Login extends Component { componentDidUpdate(prevProps) { // 当登录状态从false变为true时,跳转至dashboard if (this.props.signedIn && !prevProps.signedIn) { this.props.history.push('/dashboard'); } } // 你的登录逻辑代码... render() { // 额外处理:如果已经登录,直接渲染重定向(防止手动访问/login) if (this.props.signedIn) { return <Redirect to="/dashboard" />; } return ( // 你的登录表单代码 ); } } const mapStateToProps = state => ({ signedIn: state.auth.signedIn }); export default connect(mapStateToProps)(Login);
方案二:在App组件中添加全局路径检查
在App的render方法中,增加一段逻辑:当用户已登录且当前路径是/login时,强制重定向到/dashboard:
render() { const { signedIn } = this.props; const currentPath = window.location.pathname; // 已登录却在登录页?直接跳去仪表盘 if (signedIn && currentPath === '/login') { return <Redirect to="/dashboard" />; } console.log('AUTH:' , signedIn); return ( <div> <BrowserRouter> <Switch> <Route exact path="/" render={() => <Redirect to={signedIn ? '/dashboard' : '/login'}/>}/> <Route exact path="/login" component={Login} /> <PrivateRoute exact path="/dashboard" ><DashboardLayout/></PrivateRoute> </Switch> </BrowserRouter> </div> ); }
额外优化:添加加载状态避免闪屏
因为fetchUser是异步的,初始时用户可能会短暂看到登录页再跳走,体验不好。你可以在Redux的auth状态中加一个loading字段,在请求未完成时显示加载组件:
1. 修改Redux的auth reducer
const initialState = { signedIn: false, loading: true // 初始设为true }; const authReducer = (state = initialState, action) => { switch(action.type) { case 'FETCH_USER_START': return { ...state, loading: true }; case 'FETCH_USER_SUCCESS': return { ...state, signedIn: true, loading: false }; case 'FETCH_USER_FAILURE': return { ...state, signedIn: false, loading: false }; default: return state; } };
2. 修改App组件的render逻辑
const mapStateToProps = state => ({ signedIn: state.auth.signedIn, loading: state.auth.loading // 新增loading状态映射 }); // ... render() { const { signedIn, loading } = this.props; const currentPath = window.location.pathname; // 请求未完成时显示加载 if (loading) { return <div>Loading user info...</div>; // 可以换成你自己的加载组件 } if (signedIn && currentPath === '/login') { return <Redirect to="/dashboard" />; } console.log('AUTH:' , signedIn); return ( // 原有的路由代码 ); }
这样就能完美解决你的问题啦!
内容的提问来源于stack exchange,提问作者Mickael Zana
相关产品推荐
相关产品推荐

