你的问题不是那么容易回答的。基本上,您需要记住用户想要访问的路径,以便在用户成功通过身份验证后重定向到该路径。
我在这里为您创建了一个示例。您可以在下面找到该示例中的解释和一些代码。
因此,如果用户未通过身份验证,我们将设置应用程序状态的路径。我会修改你的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创建了一个示例。