gpt4 book ai didi

reactjs - 如何使用 TypeScript 和 React-Router 4、5 或 6 重写 protected /私有(private)路由?

转载 作者:搜寻专家 更新时间:2023-10-30 20:33:23 25 4
gpt4 key购买 nike

我试图创建一个 <PrivateRoute>如 react 路由器中所述documents使用 typescript 。谁能帮帮我?

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 不是函数

最佳答案

原始答案(2017)

(下面的更新答案)

错误可能与渲染中的输入和隐式返回有关。当你解决这个问题时,你最终会得到这样的结果:

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 月)

如果要将用户重定向到用户首先要访问的路径,则需要记住该路径,以便在身份验证成功后重定向。以下答案将指导您完成此操作:

Redirecting a user to the page they requested after successful authentication with react-router-dom

更新(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,你需要替换 RedirectNavigate .可以在此处找到重定向到最初请求的页面的完整示例:

更新(2022 年 1 月)

作为 <Routes> 的 child 需要是 <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

关于reactjs - 如何使用 TypeScript 和 React-Router 4、5 或 6 重写 protected /私有(private)路由?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47747754/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com