在打字稿中创建自己的反应路线类
Posted
技术标签:
【中文标题】在打字稿中创建自己的反应路线类【英文标题】:Create own react route class in typescript 【发布时间】:2017-07-07 16:11:59 【问题描述】:我找到了这个 (reacttraining.com) 站点,它通过一些示例解释了 react-router。但是我不能用打字稿类来做到这一点。我想要做的是扩展 Route 类来构建我自己的。现在我想在 typescript 中实现它以进行身份验证,如下面的站点示例所示。
const PrivateRoute = ( component, ...rest ) => (
<Route ...rest render=props => (
fakeAuth.isAuthenticated ? (
React.createElement(component, props)
) : (
<Redirect to=
pathname: '/login',
state: from: props.location
/>
)
)/>
)
我搜索了很多,但找不到解释要实现的功能以及调用嵌套路由的类型属性的站点。 ES6 课程也会很有帮助,谢谢。
【问题讨论】:
【参考方案1】:这是使用函数组件的一种非常简单的方法,因为新的 react 路由器版本允许您通过钩子访问所有内容:
import React from 'react'
import Redirect, Route, RouteProps from 'react-router-dom'
const PrivateRoute = (props: RouteProps) =>
const isAuthenticated = useYourSessionProviderContext()
if (isAuthenticated)
return <Route ...props />
else
return <Redirect to='/login' />
export default PrivateRoute
【讨论】:
【参考方案2】:这里提出的解决方案对我不起作用,因为我在原始路线中同时使用了 component
和 render
参数。在此解决方案中,您可以在自定义 PrivateRoute 中使用任何 Route 配置,而不仅仅是 component
参数。
import * as React from 'react';
import
Route,
Redirect,
RouteProps,
RouteComponentProps
from "react-router-dom";
interface PrivateRouteProps extends RouteProps
isAuthenticated: boolean;
export class PrivateRoute extends Route<PrivateRouteProps>
render()
return (
<Route render=(props: RouteComponentProps) =>
if(!this.props.isAuthenticated())
return <Redirect to='/login' />
if(this.props.component)
return React.createElement(this.props.component);
if(this.props.render)
return this.props.render(props);
/>
);
例子:
<PrivateRoute
path='/dashboard'
component=DashboardPage
isAuthenticated=props.isAuthenticated
/>
<PrivateRoute
path='/checkout'
isAuthenticated=props.isAuthenticated
render=() => (
<CheckoutPage auth=props.auth />
)
/>
【讨论】:
尝试使用它,但它从不执行重定向,总是呈现组件。在返回的断点处,我可以看到 this.props.isAuthenticated 为 false,但它仍然呈现组件。 也看到了这个Warning: You should not use <Route component> and <Route render> in the same route; <Route render> will be ignored
好收获。我修改了我的解决方案。【参考方案3】:
这是我使用 "react-router-dom": "^4.4.0-beta.6"
和 "typescript": "3.2.2"
的解决方案
import React, FunctionComponent from "react";
import
Route,
Redirect,
RouteProps,
RouteComponentProps
from "react-router-dom";
interface PrivateRouteProps extends RouteProps
component:
| React.ComponentType<RouteComponentProps<any>>
| React.ComponentType<any>;
const PrivateRoute: FunctionComponent<PrivateRouteProps> = (
component: Component,
...rest
) =>
return (
<Route
...rest
render=props =>
true ? ( //put your authenticate logic here
<Component ...props />
) : (
<Redirect
to=
pathname: "/signin"
/>
)
/>
);
;
export default PrivateRoute;
【讨论】:
【参考方案4】:我也在寻找同样的东西。这个问题很老,但也许有人仍在寻找它。 这是我想出的(从 react-router 4 正确使用的所有类型):
interface PrivateRouteProps extends RouteProps
component: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>
type RenderComponent = (props: RouteComponentProps<any>) => React.ReactNode;
export class PrivateRoute extends Route<PrivateRouteProps>
render ()
const component: Component, ...rest: PrivateRouteProps = this.props;
const renderComponent: RenderComponent = (props) => (
AuthenticationService.isAuthenticated()
? <Component ...props />
: <Redirect to='/login' />
);
return (
<Route ...rest render=renderComponent />
);
【讨论】:
+uno 用于在简洁的解决方案中正确使用类型。【参考方案5】:关于 Redux ...
Jacka's answer 帮助了我很多,但我很难将PrivateRoute
组件连接到 redux。此外,我想将生成的Route
组件抽象为工作,例如作为LoggedInRoute
、NotLoggedInRoute
或一般的Route
,如果满足条件则显示它的组件,否则会重定向到指定位置:
注意:使用redux
4、react-router-dom
4 和打字稿2.9
编写。
import * as H from 'history';
import * as React from 'react';
import connect, MapStateToPropsParam from 'react-redux';
import Redirect, Route, RouteComponentProps, RouteProps from 'react-router';
export interface ConditionalRouteProps extends RouteProps
routeCondition: boolean;
redirectTo: H.LocationDescriptor;
export class ConditionalRoute extends React.Component<ConditionalRouteProps>
public render()
// Extract RouteProps without component property to rest.
const component: Component, routeCondition, redirectTo, ...rest = this.props;
return <Route ...rest render=this.renderFn />
private renderFn = (renderProps: RouteComponentProps<any>) =>
if (this.props.routeCondition)
const component: Component = this.props; // JSX accepts only upprcase.
if (!Component)
return null;
return <Component ...renderProps />
return <Redirect to=this.props.redirectTo />;
;
export function connectConditionalRoute<S>(mapStateToProps: MapStateToPropsParam<ConditionalRouteProps, RouteProps, S>)
return connect<ConditionalRouteProps, , RouteProps, S>(mapStateToProps)(ConditionalRoute);
您可以使用ConditionalRoute
组件而不连接它并使用组件的本地状态,例如:
interface RootState
loggedIn: boolean;
export class Root extends React.Component<RootProps, RootState>
/* skipped initialState and setState(...) calls */
public render()
return (
<Switch>
<ConditionalRoute
path="/todos"
component=TodoPage
routeCondition=this.state.loggedIn
redirectTo="/login" />
<ConditionalRoute
path="/login"
component=LoginPage
routeCondition=!this.state.loggedIn
redirectTo="/" />
<Redirect to="/todos" />
</Switch>
);
或者使用实用函数connectConditionalRoute<S>(...)
来使用你的redux store:
const loginRoute = '/login';
const todosRoute = '/todos';
const LoggedInRoute = connectConditionalRoute<RootState>(state => (
redirectTo: loginRoute,
routeCondition: state.isLoggedIn,
));
const NotLoggedInRoute = connectConditionalRoute<RootState>(state => (
redirectTo: todosRoute,
routeCondition: !state.isLoggedIn
));
const Root: React.SFC = () => (
<Switch>
<LoggedInRoute path="/todos" component=TodoPage />
<NotLoggedInRoute path="/login" component=LoginPage />
<Redirect to="/todos" />
</Switch>
);
提供的示例中的行为:未授权用户访问/todos
,被重定向到/login
,授权用户访问/login
,被重定向到/todos
。每当 redux store 的 isLoggedIn
发生变化时,连接的组件都会更新并自动重定向用户。
【讨论】:
【参考方案6】:这是我目前为止最好的照片,虽然还有一个any
:)
import * as React from "react"
import Redirect, Route, RouteComponentProps, RouteProps from "react-router-dom"
type RouteComponent = React.StatelessComponent<RouteComponentProps<>> | React.ComponentClass<any>
const AUTHENTICATED = false // TODO: implement authentication logic
export const PrivateRoute: React.StatelessComponent<RouteProps> = (component, ...rest) =>
const renderFn = (Component?: RouteComponent) => (props: RouteProps) =>
if (!Component)
return null
if (AUTHENTICATED)
return <Component ...props />
const redirectProps =
to:
pathname: "/auth/sign-in",
state: from: props.location,
,
return <Redirect ...redirectProps />
return <Route ...rest render=renderFn(component) />
【讨论】:
感谢分享您的解决方案!将 PrivateRoute 与具有自己属性的组件一起使用的最佳方式是什么?【参考方案7】:你可以使用any
。
const PrivateRoute = (component: Component, ...rest : any) => (
<Route ...rest render=PrivateRender(Component) />
);
const PrivateRender = (Component: any) =>
return (props: any) =>
return <Component ...props/>;
;
;
【讨论】:
使用 any 只是关闭 linter,但不会在应用程序运行之前提供静态类型的好处,例如自动完成/智能感知/错误。以上是关于在打字稿中创建自己的反应路线类的主要内容,如果未能解决你的问题,请参考以下文章