Ahm*_*gdy 5 redirect typescript reactjs react-router react-router-dom
我已经构建了一个公共路由组件,用于登录以在用户未通过身份验证时显示。每当未登录的用户单击受保护的路由时,他将被重定向到登录页面,他可以在其中输入凭据。我想要一种编程方式,以便如果他使用正确的凭据登录,他应该被重定向到他首先尝试访问的页面。例如,如果用户请求个人资料页面,他应该在登录后重定向到该页面,如果用户请求设置页面,也会发生同样的情况。
截至目前,我只能将它们重定向到 home path /。有什么方法可以使用重定向,以便它知道用户请求的路径?
这是我当前的公共路由组件代码
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);
Run Code Online (Sandbox Code Playgroud)
Rob*_*bin 11
You question cannot be answered that easily. Basically you need to remember, which path a user wanted to access, so you can redirect to that path, after the user successfully authenticated.
I've created you an example here. The explanation and some code from that example you can find below.
So if the user is not authenticated, we set the path to the app state. I would modify your ProtectedRoute to this:
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 }} />;
}
};
Run Code Online (Sandbox Code Playgroud)
To remember the authentication and the redirection path I would create a context based on the following model:
export type Session = {
isAuthenticated?: boolean;
redirectPath: string;
}
export const initialSession: Session = {
redirectPath: ''
};
Run Code Online (Sandbox Code Playgroud)
According to that the context looks like this:
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>
);
}
Run Code Online (Sandbox Code Playgroud)
Now you need to make this context available to your app:
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')
);
Run Code Online (Sandbox Code Playgroud)
In your main container you can apply the protected routes:
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>
);
};
Run Code Online (Sandbox Code Playgroud)
I've updated my answer above. React was throwing an error when setting the state from a foreign component. Also the previous solution didn't work when / path was not protected. This issues should be fixed.
Additionally I've created an example for React Router 6.
| 归档时间: |
|
| 查看次数: |
5689 次 |
| 最近记录: |