这是react-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} />
连接器/专用路由
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;
组件/专用路由
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>>; }'.
答案 0 :(得分:3)
发生错误是因为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;
答案 1 :(得分:1)
当前答案有效,但是我想发布我的解决方案,因为我认为它具有一些优点:
component
的属性any
。<Route>
组件和子项道具-无需重新实现已经存在的框架逻辑/代码。react-redux
官方文档中的Recipe: Static Typing
示例:
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);
答案 2 :(得分:0)
我发现Matt's answer非常有用,但需要它同时用于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;
注意:这恰好是像原始的training article一样使用fakeAuth
而不是user1283776的isSignedIn
的redux东西,但是您明白了。
答案 3 :(得分:-1)
我将“ React.ReactNode”类型用于子组件,而不是任何子组件。