我构建了一个公共路由组件,用于登录,以便在用户未通过身份验证时显示。每当未记录的用户单击受保护的路由时,他将被重定向到登录页面,在那里他可以输入凭据。我想要一种编程方式,以便如果他使用正确的凭据登录,则应将他重定向到他首先尝试访问的页面。例如,如果用户请求配置文件页面,则应在登录后将他重定向到该页面,如果用户请求设置页面,也会发生同样的情况。
截至目前,我只能将它们重定向到家庭路径/
。有什么方法可以使用重定向,以便它知道用户请求的路径?
这是我当前用于公共路由组件的代码
export const PublicRoute = ({
isAuthenticated,
component: Component,
...rest
}: PublicRouteProps) => (
<Route
{...rest}
component={(props: any) => {
console.log(props.path);
return isAuthenticated.auth ? (
<Redirect to='/' />
) : (
<div>
<Component {...props} />
</div>
);
}}
/>
);
const mapStateToProps = (state: ReduxStoreState) => ({
isAuthenticated: state.isAuthenticated
});
export default connect(mapStateToProps)(PublicRoute);
你的问题不能那么容易回答。基本上,您需要记住用户想要访问的路径,以便在用户成功进行身份验证后重定向到该路径。
我在这里为您创建了一个示例。您可以在下面找到该示例中的说明和一些代码。
因此,如果用户未通过身份验证,我们将设置应用状态的路径。我会将您的ProtectedRoute
修改为:
import { useEffect } from 'react';
import { Redirect, Route, RouteProps, useLocation } from 'react-router';
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
redirectPath: string;
setRedirectPath: (path: string) => void;
} & RouteProps;
export default function ProtectedRoute({isAuthenticated, authenticationPath, redirectPath, setRedirectPath, ...routeProps}: ProtectedRouteProps) {
const currentLocation = useLocation();
useEffect(() => {
if (!isAuthenticated) {
setRedirectPath(currentLocation.pathname);
}
}, [isAuthenticated, setRedirectPath, currentLocation]);
if(isAuthenticated && redirectPath === currentLocation.pathname) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: isAuthenticated ? redirectPath : authenticationPath }} />;
}
};
为了记住身份验证和重定向路径,我将基于以下模型创建一个上下文:
export type Session = {
isAuthenticated?: boolean;
redirectPath: string;
}
export const initialSession: Session = {
redirectPath: ''
};
根据这一点,上下文如下所示:
import { createContext, useContext, useState } from "react";
import { initialSession, Session } from "../models/session";
export const SessionContext = createContext<[Session, (session: Session) => void]>([initialSession, () => {}]);
export const useSessionContext = () => useContext(SessionContext);
export const SessionContextProvider: React.FC = (props) => {
const [sessionState, setSessionState] = useState(initialSession);
const defaultSessionContext: [Session, typeof setSessionState] = [sessionState, setSessionState];
return (
<SessionContext.Provider value={defaultSessionContext}>
{props.children}
</SessionContext.Provider>
);
}
现在,需要将此上下文提供给应用:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './containers/App';
import { SessionContextProvider } from './contexts/SessionContext';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<SessionContextProvider>
<App />
</SessionContextProvider>
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
在主容器中,您可以应用受保护的路由:
import ProtectedRoute, { ProtectedRouteProps } from "../components/ProtectedRoute";
import { useSessionContext } from "../contexts/SessionContext";
import { Route, Switch } from 'react-router';
import Homepage from "./Homepage";
import Dashboard from "./Dashboard";
import Protected from "./Protected";
import Login from "./Login";
export default function App() {
const [sessionContext, updateSessionContext] = useSessionContext();
const setRedirectPath = (path: string) => {
updateSessionContext({...sessionContext, redirectPath: path});
}
const defaultProtectedRouteProps: ProtectedRouteProps = {
isAuthenticated: !!sessionContext.isAuthenticated,
authenticationPath: '/login',
redirectPath: sessionContext.redirectPath,
setRedirectPath: setRedirectPath
};
return (
<div>
<Switch>
<Route exact={true} path='/' component={Homepage} />
<ProtectedRoute {...defaultProtectedRouteProps} path='/dashboard' component={Dashboard} />
<ProtectedRoute {...defaultProtectedRouteProps} path='/protected' component={Protected} />
<Route path='/login' component={Login} />
</Switch>
</div>
);
};
2021 年 3 月更新
我已经更新了上面的答案。React 在从外部组件设置状态时抛出错误。此外,当路径不受保护时/
以前的解决方案也不起作用。此问题应已修复。
此外,我还为 React Router 6 创建了一个示例。
伙计我认为最好的方法是在这样的componentDidMount
中使用history.push
函数:
componentDidMount() {
if(isAuthenticated.auth) {
this.props.history.push('/profile')
}
else {
this.props.history.push('/login')
}
}
在您的应用程序中.js
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
class App extends Component {
constructor(props) {
super(props)
this.state = {
urlToRedirect: null
}
}
componentWillReceiveProps(nextProps) {
if ( nextProps.location !== this.props.location &&
!this.props.isAuthenticated &&
this.props.history.action === 'REPLACE') {
this.setState({urlToRedirect: this.props.location.pathname});
}
}
}
const mapStateToProps = (state: ReduxStoreState) => ({
isAuthenticated: state.isAuthenticated
});
export default connect(mapStateToProps, null)(withRouter(App));
您可以使用 Redux 状态,然后访问该 URL,而不是使用 setState。