Вероятно, ошибка связана с типизацией и неявным возвратом при рендеринге. Когда вы исправите это, вы получите что-то вроде этого:
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 г.)
Если вы предпочитаете писать функциональные компоненты, вы можете сделать это очень похожим образом. Это также работает с 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 г.)
Если вы хотите перенаправить пользователя на путь, к которому пользователь хотел получить доступ первым, вам необходимо запомнить путь, чтобы вы могли перенаправить после успешной аутентификации. Следующий ответ поможет вам в этом:
Перенаправление пользователя на страница, которую они запросили после успешной аутентификации с помощью response-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 Router V6, вам необходимо заменить Redirect
на Navigate
. Полный пример с перенаправлением на изначально запрошенную страницу можно найти здесь:
person
Robin
schedule
11.12.2017