这个错误可能与渲染中的键入和隐式返回有关.当你解决这个问题时,你最终会得到这样的结果:
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}
/>
上面的解决方案有一些缺点.其中一个问题是你失go 了类型安全性.
也许扩展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路由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)
上述解决方案有点过时.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路由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