Вот пример от response-router о том, как добавить компонент для защищенных маршрутов:
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
render = {props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to = {{
pathname: "/login",
state: { from: props.location }
}}
/>
)
}
/>
);
}
https://reacttraining.com/react-router/web/example/auth-workflow
Я попытался реализовать эту функциональность в моем проекте Typescript, взяв за основу приведенный выше пример.
компоненты / маршруты
import PrivateRoute from '../../connectors/PrivateRoute';
<PrivateRoute path = "/codes" component = {SomePage} />
разъемы / PrivateRoute
import { connect } from 'react-redux';
import { AppState } from 'app-types';
import PrivateRouteComponent from '../../components/PrivateRoute';
const mapStateToProps = (state: AppState) => {
const isSignedIn = state.user.isSignedIn;
return {
isSignedIn
};
};
const PrivateRoute = connect(
mapStateToProps,
null
)(PrivateRouteComponent);
export default PrivateRoute;
компоненты / PrivateRoute
import * as React from 'react';
import {
Route,
Redirect,
} from 'react-router-dom';
interface PrivateRouteProps {
// tslint:disable-next-line:no-any
component: any;
isSignedIn: boolean;
// tslint:disable-next-line:no-any
location: any;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, isSignedIn, location, ...rest } = props;
return (
<Route
{...rest}
render = {(routeProps) =>
isSignedIn ? (
<Component {...routeProps} />
) : (
<Redirect
to = {{
pathname: '/signin',
state: { from: location }
}}
/>
)
}
/>
);
};
export default PrivateRoute;
Ошибка
(105,18): Type '{ path: string; component: ConnectedComponentClass<typeof SomePage, Pick<SomePageProps, never>>; }' is not assignable to type 'Readonly<Pick<PrivateRouteProps, "location" | "component">>'.
Property 'location' is missing in type '{ path: string; component: ConnectedComponentClass<typeof SomePage, Pick<SomePageProps, never>>; }'.





Ошибка возникает из-за того, что PrivateRouteProps имеет обязательное свойство location, которое не предоставляется при использовании PrivateRoute в components/Routes.tsx. Я предполагаю, что это местоположение должно поступать от routeProps, который маршрутизатор автоматически передает функции render маршрута, как это было в исходном примере. Как только это будет исправлено, появится другая ошибка: components/Routes.tsx передает свойство paths, которое не объявлено в PrivateRouteProps. Поскольку PrivateRoute передает любую опору, о которой он не знает, в Route, PrivateRouteProps должен расширять RouteProps от react-router, чтобы PrivateRoute принимал все опоры, принятые Route.
Вот components/PrivateRoute.tsx после обоих исправлений:
import * as React from 'react';
import {
Route,
Redirect,
RouteProps,
} from 'react-router-dom';
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component: any;
isSignedIn: boolean;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, isSignedIn, ...rest } = props;
return (
<Route
{...rest}
render = {(routeProps) =>
isSignedIn ? (
<Component {...routeProps} />
) : (
<Redirect
to = {{
pathname: '/signin',
state: { from: routeProps.location }
}}
/>
)
}
/>
);
};
export default PrivateRoute;
Цель расширения RouteProps в этом случае - принять опору path, чтобы ее можно было передать на Route. Если другие компоненты, о которых вы говорите, обертывают Route и передают реквизиты таким же образом, как это делает PrivateRoute, я ожидаю, что их типы пропов должны будут расширять RouteProps; если эти компоненты не обертывают Route, то RouteProps не имеет значения.
Я нашел Мэтт ответ очень полезным, но мне нужно, чтобы он работал как с children, так и с component, поэтому изменил его следующим образом:
import * as React from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import { fakeAuth } from '../api/Auth';
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component?: any;
// tslint:disable-next-line:no-any
children?: any;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, children, ...rest } = props;
return (
<Route
{...rest}
render = {routeProps =>
fakeAuth.isAuthenticated ? (
Component ? (
<Component {...routeProps} />
) : (
children
)
) : (
<Redirect
to = {{
pathname: '/signin',
state: { from: routeProps.location },
}}
/>
)
}
/>
);
};
export default PrivateRoute;
Примечание. Это происходит с использованием fakeAuth как оригинального обучающая статья, а не с сокращением isSignedIn пользователя1283776, но вы поняли идею.
Текущие ответы работают, но я хотел бы опубликовать свое решение, так как я думаю, что у него есть несколько преимуществ:
component типом any.<Route>, так и дочерних реквизитов - без повторной реализации уже существующей логики / кода фреймворка.Recipe: Static Typing из официальной документации react-reduxПример:
import * as React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import {
Redirect,
Route,
RouteProps,
} from 'react-router-dom';
import { AppState } from '../store';
const mapState = (state: AppState) => ({
loggedIn: state.system.loggedIn,
});
const connector = connect(
mapState,
{ }
);
type PropsFromRedux = ConnectedProps<typeof connector>;
type Props = PropsFromRedux & RouteProps & {
};
const PrivateRoute: React.FC<Props> = props => {
const { loggedIn, ...rest } = props;
return ( !loggedIn ? <Redirect to = "/login/" /> :
<Route {...rest} />
);
};
export default connector(PrivateRoute);
Я использую тип «React.ReactNode» для моих дочерних компонентов вместо каких-либо.
Привет и добро пожаловать в StackOverflow! Пожалуйста, подумайте об обновлении вашего ответа, чтобы он был более ясным и конкретным в отношении того, что нужно изменить в исходном коде, который был опубликован в ответе. Рассмотрите возможность изменения кода и непосредственной публикации в обновленном и рабочем коде или до и после определенных строк, которые были изменены, вместе со ссылкой на файл, из которого они взяты. Это значительно улучшило бы этот ответ.
Это просто потрясающе! Если я могу задать дополнительный вопрос: почему мне нужно расширять PrivateRouteProps с помощью RouteProps, когда мне обычно не нужно делать это в других моих компонентах?