14

我找到了这个(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 课程也会很有帮助,谢谢。

4

7 回答 7

20

这是我迄今为止最好的镜头,虽然还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)} />
}
于 2017-11-22T17:54:58.033 回答
10

关于 Redux ...

Jacka 的回答对我帮助很大,但我很难将PrivateRoute组件连接到 redux。此外,我想将生成的Route组件抽象为例如作为 a 工作LoggedInRouteNotLoggedInRoute或者通常 a 在Route满足条件时呈现它的组件,否则重定向到指定位置:

注意:redux4、4react-router-dom和 typescript编写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 存储:

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 存储isLoggedIn发生变化时,连接的组件都会更新并自动重定向用户。

于 2018-07-21T16:48:11.143 回答
6

这是我使用"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;
于 2019-01-24T18:57:07.130 回答
3

我一直在寻找同样的东西。这个问题很老,但也许有人仍在寻找它。这是我想出的(从 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} />
    );
  }
}
于 2018-09-17T11:38:23.767 回答
3

你可以使用any.

const PrivateRoute = ({component: Component, ...rest }: any) => (
  <Route {...rest} render={PrivateRender(Component)} />
);

const PrivateRender = (Component: any) => {
  return (props: any) => {
    return <Component {...props}/>;
  };
};
于 2017-04-24T11:31:01.217 回答
0

The solutions proposed here didn't work for me because I was using both component and render params in my original Routes. In this solution you can use any configuration of Route in your custom PrivateRoute instead of only the component param.

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);
                }
            }} />
        );
    }
}

Examples:

<PrivateRoute 
    path={'/dashboard'} 
    component={DashboardPage} 
    isAuthenticated={props.isAuthenticated}
/>
<PrivateRoute 
    path={'/checkout'} 
    isAuthenticated={props.isAuthenticated}
    render={() => (
       <CheckoutPage auth={props.auth} />
    )} 
/>
于 2019-12-17T12:21:41.287 回答
0

这是使用函数组件执行此操作的一种非常简单的方法,因为新的 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


于 2021-06-05T04:43:17.617 回答