Reactjs 在Typescript项目中实现react路由器PrivateRoute

Reactjs 在Typescript项目中实现react路由器PrivateRoute,reactjs,typescript,redux,react-redux,react-router,Reactjs,Typescript,Redux,React Redux,React Router,以下是react router的一个示例,介绍如何为受保护的路由添加组件: function PrivateRoute({ component: Component, ...rest }) { return ( <Route {...rest} render={props => fakeAuth.isAuthenticated ? ( <Component {...props} />

以下是react router的一个示例,介绍如何为受保护的路由添加组件:

function PrivateRoute({ component: Component, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        fakeAuth.isAuthenticated ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: props.location }
            }}
          />
        )
      }
    />
  );
}
组件/privaterote

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;
import*as React from'React';
进口{
路线,,
重新使用
}从“反应路由器dom”;
接口PrivateRouteProps{
//tslint:禁用下一行:无任何
组成部分:任何;
伊西涅丁:布尔型;
//tslint:禁用下一行:无任何
地点:任何地点;
}
const PrivateRoute=(props:PrivateRouteProps)=>{
const{component:component,isSignedIn,location,…rest}=props;
返回(
伊西涅丁(
) : (
)
}
/>
);
};
导出默认私有路由;
错误

(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>>; }'.
(105,18):类型“{path:string;component:ConnectedComponentClass;}”不能分配给类型“Readonly”。
类型“{path:string;component:ConnectedComponentClass;}”中缺少属性“location”。

发生错误的原因是
PrivateRouteProps
具有一个必需的属性
location
,当您在
components/Routes.tsx
中使用
PrivateRoute
时,该属性未提供。我假设这个位置应该来自路由器自动传递给路由的
render
函数的
routeProps
,就像在原始示例中一样。修复后,会出现另一个错误:
components/Routes.tsx
正在传递未在
PrivateRouteProps
中声明的
paths
属性。由于
PrivateRoute
正在传递它不知道要
Route
的任何道具,
PrivateRouteProps
应该从
react router
扩展
RouteProps
,以便
PrivateRoute
接受
Route
接受的所有道具

这是两个修复后的组件/privaterout.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;
import*as React from'React';
进口{
路线,,
重新使用
路线计划,
}从“反应路由器dom”;
接口PrivateRouteProps扩展了RouteProps{
//tslint:禁用下一行:无任何
组成部分:任何;
伊西涅丁:布尔型;
}
const PrivateRoute=(props:PrivateRouteProps)=>{
const{component:component,isSignedIn,…rest}=props;
返回(
伊西涅丁(
) : (
)
}
/>
);
};
导出默认私有路由;
我发现它非常有用,但需要它来为
儿童
以及
组件
工作,因此调整如下:

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;
import*as React from'React';
从“react router dom”导入{Route,Redirect,RouteProps};
从“../api/Auth”导入{fakeAuth};
接口PrivateRouteProps扩展了RouteProps{
//tslint:禁用下一行:无任何
组件?:任何;
//tslint:禁用下一行:无任何
儿童?:任何;
}
const PrivateRoute=(props:PrivateRouteProps)=>{
const{component:component,children,…rest}=props;
返回(
伪造的。是否已验证(
组件(
) : (
儿童
)
) : (
)
}
/>
);
};
导出默认私有路由;

注意:这恰巧是像原版一样使用了
fakeAuth
而不是user1283776的
isSignedIn
redux的东西,但你明白了。

当前的答案很有效,但我想发布我的解决方案,因为我认为它有一些优点:

  • 不使用类型
    any
    覆盖属性
    组件
  • 利用来支持组件和子道具,而无需重新实现现有的框架逻辑/代码
  • 使用官方
    react redux
    文档
例如:

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);
import*as React from'React';
从'react redux'导入{connect,ConnectedProps};
进口{
重新使用
路线,,
路线计划,
}从“反应路由器dom”;
从“../store”导入{AppState};
常量映射状态=(状态:AppState)=>({
loggedIn:state.system.loggedIn,
});
常数连接器=连接(
mapState,
{ }
);
类型PropsFromRedux=已连接的PROPS;
类型Props=PropsFromRedux和RouteProps&{
};
const privaterote:React.FC=props=>{
常量{loggedIn,…rest}=props;
返回(!loggedIn?):
);
};
导出默认连接器(PrivateRoute);

我对我的子组件使用“React.ReactNode”类型,而不是任何组件。

这真是太棒了!如果我可以问一个后续问题:当我通常不需要在我的其他组件中扩展PrivateRouteProps时,我为什么需要用RouteProps扩展PrivateRouteProps?在这种情况下扩展
RouteProps
的目的是接受
路径
属性,以便将其传递到
路由
。如果您正在谈论的其他组件以与PrivateRoute相同的方式包裹
路由
并传递道具,我希望它们的道具类型需要扩展
路由路径
;如果这些组件没有包装
Route
,则
RouteProps
不相关。您好,欢迎使用StackOverflow!请考虑更新您的答案,以便更清楚和具体地说明在答案中张贴的原始代码中要修改的内容。考虑修改代码,并直接在更新的和工作的代码中,或更改的特定行的前后,以及对它们来自哪一个文件的引用。这将大大改善这个答案。
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);