如何使用 TypeScript 和 React-Router 4、5 或 6 重写 protected/private 路由?
How to rewrite the protected/private route using TypeScript and React-Router 4, 5 or 6?
我正在尝试使用 TypeScript 创建一个 <PrivateRoute>
,如 react-router documents 中所述。谁能帮帮我?
react-router文档中的privateRoute:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{pathname: '/login', state: { from: props.location }
}}/>
)
)}/>
)
下面是我的 TypeScript 版本(它不会工作):
const PrivateRoute = (theProps: { path: string, component: React.SFC<RouteComponentProps<any> | undefined> | React.ComponentClass<RouteComponentProps<any> | undefined> }) => {
return <Route path={theProps.path} render={props => (
fakeAuth.isAuthenticated ? (
<React.Component {...theProps} /> <!-- **** It will raise error *** -->
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}} />
)
)} />
}
<React.Component {...thisProps} />
不对。错误是:NodeInvocationException: inst.render 不是函数
TypeError: inst.render 不是一个函数
错误可能与渲染中的输入和隐式 return 有关。当你解决这个问题时,你最终会得到这样的结果:
const PrivateRoute = ({component, isAuthenticated, ...rest}: any) => {
const routeComponent = (props: any) => (
isAuthenticated
? React.createElement(component, props)
: <Redirect to={{pathname: '/login'}}/>
);
return <Route {...rest} render={routeComponent}/>;
};
这个组件可以这样使用:
<PrivateRoute
path='/private'
isAuthenticated={this.props.state.session.isAuthenticated}
component={PrivateContainer}
/>
上述解决方案有一些缺点。其中之一是您失去了类型安全性。
可能扩展 Route
组件是更好的主意。
import * as React from 'react';
import {Redirect, Route, RouteProps} from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
authenticationPath: string;
}
export class ProtectedRoute extends Route<ProtectedRouteProps> {
public render() {
let redirectPath: string = '';
if (!this.props.isAuthenticated) {
redirectPath = this.props.authenticationPath;
}
if (redirectPath) {
const renderComponent = () => (<Redirect to={{pathname: redirectPath}}/>);
return <Route {...this.props} component={renderComponent} render={undefined}/>;
} else {
return <Route {...this.props}/>;
}
}
}
所以你可以像这样使用组件:
const defaultProtectedRouteProps: ProtectedRouteProps = {
isAuthenticated: this.props.state.session.isAuthenticated,
authenticationPath: '/login',
};
<ProtectedRoute
{...defaultProtectedRouteProps}
exact={true}
path='/'
component={ProtectedContainer}
/>
更新(2019 年 11 月)
如果您更喜欢编写功能组件,您可以采用非常相似的方式来编写。这也适用于 React Router 5:
import * as React from 'react';
import { Redirect, Route, RouteProps } from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
isAllowed: boolean;
restrictedPath: string;
authenticationPath: string;
}
export const ProtectedRoute: React.FC<ProtectedRouteProps> = props => {
let redirectPath = '';
if (!props.isAuthenticated) {
redirectPath = props.authenticationPath;
}
if (props.isAuthenticated && !props.isAllowed) {
redirectPath = props.restrictedPath;
}
if (redirectPath) {
const renderComponent = () => <Redirect to={{ pathname: redirectPath }} />;
return <Route {...props} component={renderComponent} render={undefined} />;
} else {
return <Route {...props} />;
}
};
export default ProtectedRoute;
更新(2019 年 12 月)
如果要将用户重定向到用户首先要访问的路径,则需要记住该路径,以便在身份验证成功后重定向。以下答案将指导您完成此过程:
更新(2021 年 3 月)
上面的解决方案有点过时了。 ProtectedRoute组件可以简单的写成如下:
import { Redirect, Route, RouteProps } from 'react-router';
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
} & RouteProps;
export default function ProtectedRoute({isAuthenticated, authenticationPath, ...routeProps}: ProtectedRouteProps) {
if(isAuthenticated) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: authenticationPath }} />;
}
};
如果您使用 React Router V6,您需要将 Redirect
替换为 Navigate
。可以在此处找到重定向到最初请求页面的完整示例:
更新(2022 年 1 月)
由于 <Routes>
的子元素需要是 <Route>
个元素,因此 <ProtectedRoute>
可以更改为:
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
outlet: JSX.Element;
};
export default function ProtectedRoute({isAuthenticated, authenticationPath, outlet}: ProtectedRouteProps) {
if(isAuthenticated) {
return outlet;
} else {
return <Navigate to={{ pathname: authenticationPath }} />;
}
};
<ProtectedRoute>
现在可以像下面这样应用:
const defaultProtectedRouteProps: Omit<ProtectedRouteProps, 'outlet'> = {
isAuthenticated: !!sessionContext.isAuthenticated,
authenticationPath: '/login',
};
return (
<div>
<Routes>
<Route path='/' element={<Homepage />} />
<Route path='dashboard' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Dashboard />} />} />
<Route path='protected' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Protected />} />} />
<Route path='nested' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Layout />} />}>
<Route path='one' element={<Protected />} />
<Route path='two' element={<Protected />} />
</Route>
<Route path='login' element={<Login />} />
</Routes>
</div>
);
我也更新了 React Router 6 example。到目前为止,甚至还有关于此的官方指南:https://reactrouter.com/docs/en/v6/examples/auth
您仍然可以使用 SFC 表单,我发现它更简洁一些。只需将您需要的任何道具与 RouteProps
混合即可:
const PrivateRoute: React.SFC<RouteProps> = ({
component: Component,
...rest
}: {
component: React.ComponentType<RouteProps>;
}) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated
? <Component {...props} />
: <Redirect to="/login" />
}
/>
);
我的私人路线
import React from 'react'
import {Redirect, Route, RouteProps} from 'react-router'
export interface IPrivateRouteProps extends RouteProps {
isAuth: boolean // is authenticate route
redirectPath: string // redirect path if don't authenticate route
}
const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
return props.isAuth ? (
<Route {...props} component={props.component} render={undefined} />
) : (
<Redirect to={{pathname: props.redirectPath}} />
)
}
export default PrivateRoute
正在使用
<PrivateRoute isAuth={false} redirectPath="/login" path="/t1">
<Pages.Profile /> your`s protected page
</PrivateRoute>
这对我很有帮助
import * as React from "react";
import { Route } from "react-router-dom";
interface IProps {
exact?: boolean;
path: string;
component: React.ComponentType<any>;
}
const LoggedOutRoute = ({
component: Component,
...otherProps
}: IProps) => (
<>
<header>Logged Out Header</header>
<Route
render={otherProps => (
<>
<Component {...otherProps} />
</>
)}
/>
<footer>Logged Out Footer</footer>
</>
);
export default LoggedOutRoute;
我们可以像下面这样写,而无需在 tsx.xml 中提供非常明确和准确的类型或接口。只需写成 -{ component: Component, ...rest }: any- 作为类型,我们就完成了。
export default function PrivateRoute({ component: Component, ...rest }: any) {
const { currentUser } = useAuth();
return (
<Route
{...rest}
render={(props) => {
return currentUser ? (
<Component {...props} />
) : (
<Redirect to="/login" />
);
}}
></Route>
);
}
这很简洁。
import React from "react";
import { Route, Redirect, RouteProps } from "react-router-dom";
import { RoutePaths } from "./RoutePaths";
interface Props extends RouteProps {
isLoggedIn: boolean;
}
const AuthRoute: React.FC<Props> = ({ component: Component, ...rest }) => {
if (!Component) {
return null;
}
const { isLoggedIn } = rest;
return (
<Route
{...rest}
render={(props) =>
isLoggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: RoutePaths.Auth,
/**
* For redirecting after login.
*/
state: { from: props.location },
}}
/>
)
}
/>
);
};
export default AuthRoute;
似乎从 react-router-dom 6.0.0-beta.4 开始对我有用:
App.tsx
import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom';
interface Props {}
export const App: React.FC<Props> = ({}) => {
const isAuthenticated = true;
return (
<Router>
<Routes>
<Route path={`/`} element={isAuthenticated ? <AuthenticatedPage /> : <Navigate to={`/auth`} />} />
<Route path={`/auth`} element={<AuthenticationPage />} />
</Routes>
</Router>
);
};
对于 react-router-dom (v6.0.2) ,您可以将以下代码用于您的 PrivateRoute 组件:
import { FC } from 'react';
import { useAppSelector } from 'app/hooks';
import { Navigate } from 'react-router-dom';
interface PropType {
component: React.FC;
}
const PrivateRoute: FC<PropType> = ({ component: Component }) => {
const { isAuthenticated } = useAppSelector(state => state.auth);
if (isAuthenticated) return <Component />;
return <Navigate to='/login' />;
};
export default PrivateRoute;
要在你的App.tsx中使用,你可以按如下方式使用它:
<Routes>
<Route path='/' element={<LandingPage />} />
<Route path='/login' element={<LoginPage />} />
<Route path='/home' element={<PrivateRoute component={HomePage} />} />
<Route path='*' element={<NotFound />} />
</Routes>
只是添加对我有用的内容:
interface PrivateRouteProps extends RouteProps {
component: React.FC<RouteProps>;
path: string;
}
export default function PrivateRoute({
component: Component,
path,
}: PrivateRouteProps) {
return (
<Route
path={path}
render={(props) =>
localStorage.getItem('user') ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: '/login', state: { from: props.location } }}
/>
)
}
/>
);
}
并且可以这样使用:
<PrivateRoute path="/user/dashboard" component={Dashboard} />
快速代码片段:
PrivateRote.tsx
import React from 'react'
import { Route, Redirect, RouteProps } from 'react-router-dom'
import { useLogin} from 'hooks'
interface PrivateRouteProps extends RouteProps {
component: any
}
export const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, ...rest } = props
const { isLogin} = useLogin() //true/false or something else
return account ? <Route {...rest} render={props => <Component {...props} />} /> : <Redirect to="/" />
}
usage in App.tsx
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/faq" component={Faq} />
<PrivateRoute exact path="/profile" component={Profile} />
</Switch>
</Router>
使用 React-router-dom 的 v6,我们以这种格式处理受保护的路由
设置授权保护组件
import React from "react";
import { Navigate, useLocation, useNavigate } from "react-router-dom";
import { useAppSelector } from "../../state/hooks";
const ProtectedRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const {user} = <Your-State-Provider>// Redux/Context or even in-memory user
const location = useLocation();
return !user.isAuthenticated ? (
<Navigate to={"/login"} state={{ from: location }} replace />
) : (
children
);
};
export default ProtectedRoute;
在此基本上将检查用户身份验证状态,然后根据该条件我们使用 <Navigate/>
重定向回登录页面。我们获取当前位置并将其传递给 Navigate
以便我们在用户登录后自动将其重定向到预期页面。我们重组 children
道具并在用户通过身份验证时呈现 children
。这样做的好处是我们只需要用 <ProtectedRoute>{children}</ProtectedRoute>
.
包裹我们想要渲染的元素
使用受保护的路由
import { Fragment } from "react";
import ProtectedRoute from "./components/ProtectedRoute/ProtectedRoute";//Your protected route
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Login from "./pages/Login/Login";
import MainPage from "./pages/MainPage/MainPage";
const App = () => {
return (
<Router>
<Fragment>
<nav>
<Link to="/admin" />
</nav>
<Routes>
<Route
path="/"
element={
<ProtectedRoute>
<MainPage />
</ProtectedRoute>
}
/>
<Route path="/login" element={<Login />} />
</Routes>
</Fragment>
</Router>
);
};
export default App;
因为 react-router-dom v6
允许在路由中嵌套组件,现在我们只需用 ProtectedRoute
包裹我们想要保护的组件,例如
<Route path="/" element={ <ProtectedRoute><Your-Protected-page /></ProtectedRoute>}/>
我正在尝试使用 TypeScript 创建一个 <PrivateRoute>
,如 react-router documents 中所述。谁能帮帮我?
react-router文档中的privateRoute:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
fakeAuth.isAuthenticated ? (
<Component {...props}/>
) : (
<Redirect to={{pathname: '/login', state: { from: props.location }
}}/>
)
)}/>
)
下面是我的 TypeScript 版本(它不会工作):
const PrivateRoute = (theProps: { path: string, component: React.SFC<RouteComponentProps<any> | undefined> | React.ComponentClass<RouteComponentProps<any> | undefined> }) => {
return <Route path={theProps.path} render={props => (
fakeAuth.isAuthenticated ? (
<React.Component {...theProps} /> <!-- **** It will raise error *** -->
) : (
<Redirect to={{
pathname: '/',
state: { from: props.location }
}} />
)
)} />
}
<React.Component {...thisProps} />
不对。错误是:NodeInvocationException: inst.render 不是函数
TypeError: inst.render 不是一个函数
错误可能与渲染中的输入和隐式 return 有关。当你解决这个问题时,你最终会得到这样的结果:
const PrivateRoute = ({component, isAuthenticated, ...rest}: any) => {
const routeComponent = (props: any) => (
isAuthenticated
? React.createElement(component, props)
: <Redirect to={{pathname: '/login'}}/>
);
return <Route {...rest} render={routeComponent}/>;
};
这个组件可以这样使用:
<PrivateRoute
path='/private'
isAuthenticated={this.props.state.session.isAuthenticated}
component={PrivateContainer}
/>
上述解决方案有一些缺点。其中之一是您失去了类型安全性。
可能扩展 Route
组件是更好的主意。
import * as React from 'react';
import {Redirect, Route, RouteProps} from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
authenticationPath: string;
}
export class ProtectedRoute extends Route<ProtectedRouteProps> {
public render() {
let redirectPath: string = '';
if (!this.props.isAuthenticated) {
redirectPath = this.props.authenticationPath;
}
if (redirectPath) {
const renderComponent = () => (<Redirect to={{pathname: redirectPath}}/>);
return <Route {...this.props} component={renderComponent} render={undefined}/>;
} else {
return <Route {...this.props}/>;
}
}
}
所以你可以像这样使用组件:
const defaultProtectedRouteProps: ProtectedRouteProps = {
isAuthenticated: this.props.state.session.isAuthenticated,
authenticationPath: '/login',
};
<ProtectedRoute
{...defaultProtectedRouteProps}
exact={true}
path='/'
component={ProtectedContainer}
/>
更新(2019 年 11 月)
如果您更喜欢编写功能组件,您可以采用非常相似的方式来编写。这也适用于 React Router 5:
import * as React from 'react';
import { Redirect, Route, RouteProps } from 'react-router';
export interface ProtectedRouteProps extends RouteProps {
isAuthenticated: boolean;
isAllowed: boolean;
restrictedPath: string;
authenticationPath: string;
}
export const ProtectedRoute: React.FC<ProtectedRouteProps> = props => {
let redirectPath = '';
if (!props.isAuthenticated) {
redirectPath = props.authenticationPath;
}
if (props.isAuthenticated && !props.isAllowed) {
redirectPath = props.restrictedPath;
}
if (redirectPath) {
const renderComponent = () => <Redirect to={{ pathname: redirectPath }} />;
return <Route {...props} component={renderComponent} render={undefined} />;
} else {
return <Route {...props} />;
}
};
export default ProtectedRoute;
更新(2019 年 12 月)
如果要将用户重定向到用户首先要访问的路径,则需要记住该路径,以便在身份验证成功后重定向。以下答案将指导您完成此过程:
更新(2021 年 3 月)
上面的解决方案有点过时了。 ProtectedRoute组件可以简单的写成如下:
import { Redirect, Route, RouteProps } from 'react-router';
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
} & RouteProps;
export default function ProtectedRoute({isAuthenticated, authenticationPath, ...routeProps}: ProtectedRouteProps) {
if(isAuthenticated) {
return <Route {...routeProps} />;
} else {
return <Redirect to={{ pathname: authenticationPath }} />;
}
};
如果您使用 React Router V6,您需要将 Redirect
替换为 Navigate
。可以在此处找到重定向到最初请求页面的完整示例:
更新(2022 年 1 月)
由于 <Routes>
的子元素需要是 <Route>
个元素,因此 <ProtectedRoute>
可以更改为:
export type ProtectedRouteProps = {
isAuthenticated: boolean;
authenticationPath: string;
outlet: JSX.Element;
};
export default function ProtectedRoute({isAuthenticated, authenticationPath, outlet}: ProtectedRouteProps) {
if(isAuthenticated) {
return outlet;
} else {
return <Navigate to={{ pathname: authenticationPath }} />;
}
};
<ProtectedRoute>
现在可以像下面这样应用:
const defaultProtectedRouteProps: Omit<ProtectedRouteProps, 'outlet'> = {
isAuthenticated: !!sessionContext.isAuthenticated,
authenticationPath: '/login',
};
return (
<div>
<Routes>
<Route path='/' element={<Homepage />} />
<Route path='dashboard' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Dashboard />} />} />
<Route path='protected' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Protected />} />} />
<Route path='nested' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Layout />} />}>
<Route path='one' element={<Protected />} />
<Route path='two' element={<Protected />} />
</Route>
<Route path='login' element={<Login />} />
</Routes>
</div>
);
我也更新了 React Router 6 example。到目前为止,甚至还有关于此的官方指南:https://reactrouter.com/docs/en/v6/examples/auth
您仍然可以使用 SFC 表单,我发现它更简洁一些。只需将您需要的任何道具与 RouteProps
混合即可:
const PrivateRoute: React.SFC<RouteProps> = ({
component: Component,
...rest
}: {
component: React.ComponentType<RouteProps>;
}) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated
? <Component {...props} />
: <Redirect to="/login" />
}
/>
);
我的私人路线
import React from 'react'
import {Redirect, Route, RouteProps} from 'react-router'
export interface IPrivateRouteProps extends RouteProps {
isAuth: boolean // is authenticate route
redirectPath: string // redirect path if don't authenticate route
}
const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
return props.isAuth ? (
<Route {...props} component={props.component} render={undefined} />
) : (
<Redirect to={{pathname: props.redirectPath}} />
)
}
export default PrivateRoute
正在使用
<PrivateRoute isAuth={false} redirectPath="/login" path="/t1">
<Pages.Profile /> your`s protected page
</PrivateRoute>
这对我很有帮助
import * as React from "react";
import { Route } from "react-router-dom";
interface IProps {
exact?: boolean;
path: string;
component: React.ComponentType<any>;
}
const LoggedOutRoute = ({
component: Component,
...otherProps
}: IProps) => (
<>
<header>Logged Out Header</header>
<Route
render={otherProps => (
<>
<Component {...otherProps} />
</>
)}
/>
<footer>Logged Out Footer</footer>
</>
);
export default LoggedOutRoute;
我们可以像下面这样写,而无需在 tsx.xml 中提供非常明确和准确的类型或接口。只需写成 -{ component: Component, ...rest }: any- 作为类型,我们就完成了。
export default function PrivateRoute({ component: Component, ...rest }: any) {
const { currentUser } = useAuth();
return (
<Route
{...rest}
render={(props) => {
return currentUser ? (
<Component {...props} />
) : (
<Redirect to="/login" />
);
}}
></Route>
);
}
这很简洁。
import React from "react";
import { Route, Redirect, RouteProps } from "react-router-dom";
import { RoutePaths } from "./RoutePaths";
interface Props extends RouteProps {
isLoggedIn: boolean;
}
const AuthRoute: React.FC<Props> = ({ component: Component, ...rest }) => {
if (!Component) {
return null;
}
const { isLoggedIn } = rest;
return (
<Route
{...rest}
render={(props) =>
isLoggedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: RoutePaths.Auth,
/**
* For redirecting after login.
*/
state: { from: props.location },
}}
/>
)
}
/>
);
};
export default AuthRoute;
似乎从 react-router-dom 6.0.0-beta.4 开始对我有用:
App.tsx
import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom';
interface Props {}
export const App: React.FC<Props> = ({}) => {
const isAuthenticated = true;
return (
<Router>
<Routes>
<Route path={`/`} element={isAuthenticated ? <AuthenticatedPage /> : <Navigate to={`/auth`} />} />
<Route path={`/auth`} element={<AuthenticationPage />} />
</Routes>
</Router>
);
};
对于 react-router-dom (v6.0.2) ,您可以将以下代码用于您的 PrivateRoute 组件:
import { FC } from 'react';
import { useAppSelector } from 'app/hooks';
import { Navigate } from 'react-router-dom';
interface PropType {
component: React.FC;
}
const PrivateRoute: FC<PropType> = ({ component: Component }) => {
const { isAuthenticated } = useAppSelector(state => state.auth);
if (isAuthenticated) return <Component />;
return <Navigate to='/login' />;
};
export default PrivateRoute;
要在你的App.tsx中使用,你可以按如下方式使用它:
<Routes>
<Route path='/' element={<LandingPage />} />
<Route path='/login' element={<LoginPage />} />
<Route path='/home' element={<PrivateRoute component={HomePage} />} />
<Route path='*' element={<NotFound />} />
</Routes>
只是添加对我有用的内容:
interface PrivateRouteProps extends RouteProps {
component: React.FC<RouteProps>;
path: string;
}
export default function PrivateRoute({
component: Component,
path,
}: PrivateRouteProps) {
return (
<Route
path={path}
render={(props) =>
localStorage.getItem('user') ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: '/login', state: { from: props.location } }}
/>
)
}
/>
);
}
并且可以这样使用:
<PrivateRoute path="/user/dashboard" component={Dashboard} />
快速代码片段:
PrivateRote.tsx
import React from 'react'
import { Route, Redirect, RouteProps } from 'react-router-dom'
import { useLogin} from 'hooks'
interface PrivateRouteProps extends RouteProps {
component: any
}
export const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, ...rest } = props
const { isLogin} = useLogin() //true/false or something else
return account ? <Route {...rest} render={props => <Component {...props} />} /> : <Redirect to="/" />
}
usage in App.tsx
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/faq" component={Faq} />
<PrivateRoute exact path="/profile" component={Profile} />
</Switch>
</Router>
使用 React-router-dom 的 v6,我们以这种格式处理受保护的路由
设置授权保护组件
import React from "react";
import { Navigate, useLocation, useNavigate } from "react-router-dom";
import { useAppSelector } from "../../state/hooks";
const ProtectedRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const {user} = <Your-State-Provider>// Redux/Context or even in-memory user
const location = useLocation();
return !user.isAuthenticated ? (
<Navigate to={"/login"} state={{ from: location }} replace />
) : (
children
);
};
export default ProtectedRoute;
在此基本上将检查用户身份验证状态,然后根据该条件我们使用 <Navigate/>
重定向回登录页面。我们获取当前位置并将其传递给 Navigate
以便我们在用户登录后自动将其重定向到预期页面。我们重组 children
道具并在用户通过身份验证时呈现 children
。这样做的好处是我们只需要用 <ProtectedRoute>{children}</ProtectedRoute>
.
使用受保护的路由
import { Fragment } from "react";
import ProtectedRoute from "./components/ProtectedRoute/ProtectedRoute";//Your protected route
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Login from "./pages/Login/Login";
import MainPage from "./pages/MainPage/MainPage";
const App = () => {
return (
<Router>
<Fragment>
<nav>
<Link to="/admin" />
</nav>
<Routes>
<Route
path="/"
element={
<ProtectedRoute>
<MainPage />
</ProtectedRoute>
}
/>
<Route path="/login" element={<Login />} />
</Routes>
</Fragment>
</Router>
);
};
export default App;
因为 react-router-dom v6
允许在路由中嵌套组件,现在我们只需用 ProtectedRoute
包裹我们想要保护的组件,例如
<Route path="/" element={ <ProtectedRoute><Your-Protected-page /></ProtectedRoute>}/>