React JS:私有路由刷新时保留URI,实现登录后重定向至原访问页面
解决方案:让用户登录后自动跳转到最初访问的页面
这个问题的核心是没有在重定向到登录页时保存用户原本想要访问的路径,导致登录成功后只能跳转到固定页面,没法回到用户最初想去的地方。咱们分三步搞定:
1. 实现路由守卫组件(PrivateRoute),拦截未登录访问并保存目标路径
首先你需要一个路由守卫,用来检查用户登录状态,未登录时把用户当前访问的路径存在路由state里,再重定向到登录页。
先取消App.js里PrivateRoute的注释,然后实现这个组件:
// features/shared/hoc/PrivateRoute/PrivateRoute.js import React from 'react'; import { Route, Redirect } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { userData } from '../../login-page/slices/userSlice'; const PrivateRoute = ({ component: Component, ...rest }) => { const user = useSelector(userData); const isUserSignedIn = user.userSignedIn; return ( <Route {...rest} render={(props) => isUserSignedIn ? ( <Component {...props} /> ) : ( <Redirect to={{ pathname: '/', state: { from: props.location } // 把用户原本要去的路径存在state里 }} /> ) } /> ); }; export default PrivateRoute;
2. 修改App.js的路由配置,用PrivateRoute保护需要登录的页面
把所有需要登录才能访问的路由都用PrivateRoute包裹,替换原来的Route:
// App.js import React from 'react'; import './App.scss'; import { Route, Switch, withRouter, Redirect } from 'react-router-dom'; import Layout from './features/shared/hoc/Layout/Layout'; import LoginPage from './features/login-page/login'; import { FRONTEND_ROUTES } from './features/shared/backend/frontendRoutes'; import { ComponentRoutes } from './AppRoutes'; import { useSelector } from 'react-redux'; import { userData } from './features/login-page/slices/userSlice'; import PrivateRoute from './features/shared/hoc/PrivateRoute/PrivateRoute'; // 取消注释 function App(props) { const user = useSelector(userData); const isUserSignedIn = user.userSignedIn; let routes; if (isUserSignedIn) { routes = ( <Switch> <PrivateRoute exact path={FRONTEND_ROUTES.CONFIG_PAGE} component={ComponentRoutes.asyncConfig} /> <PrivateRoute exact path={FRONTEND_ROUTES.CONFIG_PAGE_REST} component={ComponentRoutes.asyncConfig} /> <PrivateRoute exact path={FRONTEND_ROUTES.ADVERTISERS_PAGE} component={ComponentRoutes.asyncView} /> <PrivateRoute exact path={FRONTEND_ROUTES.VIEWS_PAGE} component={ComponentRoutes.asyncAdvertiserPage} /> <PrivateRoute exact path='/schedule' component={ComponentRoutes.asyncConstruction} /> <Route exact path='/' component={LoginPage} /> <Route path='/' component={ComponentRoutes.asyncNotFound} /> <Redirect to='/' /> </Switch> ); } else { routes = ( <Switch> <PrivateRoute exact path='/view' component={ComponentRoutes.asyncView} /> <Route exact path='/' component={LoginPage} /> <Redirect to='/' /> </Switch> ); } return ( <div> <Layout>{routes}</Layout> </div> ); } export default withRouter(App);
3. 修改LoginPage,登录成功后跳转到保存的目标路径
在LoginPage里拿到之前存在state里的目标路径,登录成功后自动跳转到那里:
// LoginPage.jsx import React from 'react'; import classes from './Login.module.scss'; import GoogleLogin from 'react-google-login'; import { processUserLogin, userData } from './slices/userSlice'; import { useDispatch, useSelector } from 'react-redux'; import { Redirect } from 'react-router-dom'; import Spinner from '../shared/ui-components/spinner/spinner'; export default function Login(props) { const dispatch = useDispatch(); const user = useSelector(userData); const isPending = user.status === 'loading'; // 获取用户原本要访问的路径,默认跳转到/view const targetPath = props.location.state?.from || { pathname: '/view' }; const responseGoogleSuccess = (response) => { const payload = { operationType: 'configureUserAndGetDetails', payLoad: { email: response.profileObj.email, google_payload: response, }, }; dispatch(processUserLogin(payload)); }; const responseGoogleFailed = (response) => { console.log('User Login Failed = ', response); }; return ( <div className={classes.LoginPage}> {isPending && <Spinner />} {user.userSignedIn ? ( <Redirect to={targetPath} /> // 跳转到保存的目标路径 ) : ( <GoogleLogin clientId={process.env.REACT_APP_GOOGLE_OAUTH_CLIENT_ID} buttonText='Login' onSuccess={responseGoogleSuccess} onFailure={responseGoogleFailed} cookiePolicy={'single_host_origin'} isSignedIn={true} /> )} </div> ); }
原理说明
- 当用户访问受保护页面(比如
/home/view)时,PrivateRoute会检查登录状态,未登录就把当前路径存在state.from里,再重定向到登录页。 - 登录页拿到这个
state.from,登录成功后就跳转到这个路径,而不是固定的/view。 - 即使是
isSignedIn=true触发的自动登录,只要登录成功,userSignedIn变为true,就会自动跳转到目标路径。
内容的提问来源于stack exchange,提问作者Shivam Sahil
相关产品推荐
相关产品推荐

