[英]Implement react-router PrivateRoute in Typescript project
以下是 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>>; }'.
發生該錯誤的原因是PrivateRouteProps
具有在components/Routes.tsx
使用PrivateRoute
時未提供的必需屬性location
。 我假設這個位置應該來自路由器自動傳遞給路由的render
函數的routeProps
,就像它在原始示例中所做的那樣。 修復此問題后,會暴露另一個錯誤: components/Routes.tsx
正在傳遞未在PrivateRouteProps
聲明的paths
屬性。 由於PrivateRoute
正在將它不知道的任何道具傳遞給Route
,因此PrivateRouteProps
應該從react-router
擴展RouteProps
,以便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;
我發現馬特的回答非常有用,但需要它為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
而不是 user1283776 的isSignedIn
redux 東西,但你明白了。
當前的答案有效,但我想發布我的解決方案,因為我認為它有幾個優點:
any
的屬性component
。<Route>
組件和子道具 - 無需重新實現已經存在的框架邏輯/代碼。Recipe: Static Typing
來自官方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);
我對我的子組件使用“React.ReactNode”類型而不是任何類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.