Create own react route class in typescript Create own react route class in typescript typescript typescript

Create own react route class in typescript


Here's my best shot so far, although there's still one any remaining :)

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


Regarding Redux ...

Jacka's answer helped me alot, but i had a difficult time connecting the PrivateRoute component to redux. Furthermore i wanted to abstract the resulting Route component to work e.g. as a LoggedInRoute, NotLoggedInRoute or in general a Route which presents it's component if a condition is fulfilled or redirects to a specified location otherwise:

Note: Written with redux 4, react-router-dom 4 and 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);}

You can either use the ConditionalRoute component without connecting it and use your component's local state, e.g.:

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

Or use the utility function connectConditionalRoute<S>(...) to use your 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>);

The behaviour in the provided sample: Unauthorized users visit /todos, get redirected to /login, authorized users visit /login, get redirected to /todos. Whenever the redux store's isLoggedIn changes, the connected components are updated and redirect the user automatically.


here is my solution using "react-router-dom": "^4.4.0-beta.6" and "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;