使用 Typescript 和 React 在私有路由中传递组件道具 [英] Pass component props in Private Route with Typescript and React

查看:71
本文介绍了使用 Typescript 和 React 在私有路由中传递组件道具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 React Router v4 中的 Route 组件的渲染道具通过 Typescript 和 React 实现经过身份验证的路由.

I am implementing Authenticated Routes with Typescript and React using the render props of the Route component from React Router v4.

路线:

import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { ROUTES } from 'utils/constants';
import HomePage from 'components/pages/Home';
import GuestLogin from 'components/pages/GuestLogin';
import ProfilePage from 'components/pages/Profile';
import NotFoundPage from 'components/pages/NotFound';
import ResetPassword from 'components/pages/ResetPassword';
import SetPassword from 'components/pages/SetPassword';
import LoginContainer from 'containers/Login';
import PrivateRoute from './PrivateRoute';

const Routes: React.FunctionComponent = () => (
  <Switch>
    <Route path={ROUTES.LOGIN} component={LoginContainer} exact></Route>
    <PrivateRoute
      path={ROUTES.HOME}
      component={HomePage}
    ></PrivateRoute>
    <Route path={ROUTES.GUEST_LOGIN} component={GuestLogin}></Route>
    <Route path={ROUTES.RESET_PASSWORD} component={ResetPassword}></Route>
    <Route path={ROUTES.SET_PASSWORD} component={SetPassword}></Route>
    <Route path={ROUTES.PROFILE} component={ProfilePage}></Route>
    <Route component={NotFoundPage}></Route>
  </Switch>
);

export default Routes;

私人路线:

import React from 'react';    
import { useAppContext } from 'containers/App/AppContext';
import { RouteProps, Route, Redirect } from 'react-router-dom';
import { ROUTES } from 'utils/constants';

const PrivateRoute: React.FunctionComponent<RouteProps> = ({
  component: Component,
  ...routeProps
}) => {
  const { isSignedIn } = useAppContext();
  const ComponentToRender = Component as React.ElementType;
  return (
    <Route
      {...routeProps}
      render={(props) =>
        isSignedIn ? (
          <ComponentToRender {...props} />
        ) : (
          <Redirect to={ROUTES.LOGIN} />
        )
      }
    />
  );
};

export default PrivateRoute;

问题是我想调用 props 上的 Component 集,但是,每次我尝试这个时,Typescript 都会抛出以下错误.

The problem is that I want to call the Component set on the props, however, every time I try this, Typescript throws the following error.

JSX element type 'Component' does not have any construct or call signatures.  TS2604

错误图片

原因似乎是 Route 的组件类型不是 Typescript 所期望的类型,如下所述:https://github.com/microsoft/TypeScript/issues/28631,因此我刚刚创建了一个具有新类型(ComponentToRender)的副本.

The reason seems to be that the component type for the Route is not the one Typescript expects as explained here: https://github.com/microsoft/TypeScript/issues/28631, therefore I just created a copy which has a new type(ComponentToRender).

有没有更好的方法来实现这一点?也许会覆盖 RouteProps 组件元素?

Is there a better way to implement this? Maybe overwriting the RouteProps component element?

谢谢!

推荐答案

我终于明白错误并解决了!关键是组件属性和渲染函数的处理方式不同.通过使用 RouteProps ,Typescript 编译器实际上将组件道具设置为 ComponentType(根据 RouterProps 为组件"指定的类型),它不能用于渲染功能,如索引中所示.d.ts 文件.

I finally understood the error and solved it! The key was that the component attribute and render function are handled differently type-wise. By using RouteProps , the Typescript compiler is actually setting the component props as ComponentType (the type specified for 'component' according to RouterProps), which cannot be used for the render function, as seem in the index.d.ts file.

export interface RouteProps {
    location?: H.Location;
    component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
    render?: (props: RouteComponentProps<any>) => React.ReactNode;
    children?: ((props: RouteChildrenProps<any>) => React.ReactNode) | React.ReactNode;
    path?: string | string[];
    exact?: boolean;
    sensitive?: boolean;
    strict?: boolean;
}

仅通过将渲染函数移动到 Routes 文件而不使用 PrivateRoute 组件,这种行为就会变得明显.下面的代码按预期工作,因为编译器正确推断了类型 (React.ReactNode).

This behaviour becomes apparent just by moving the render function into the Routes file and not using the PrivateRoute component. The code below works as expected, because the compiler infers the type correctly (React.ReactNode).

<Route
  path={ROUTES.POINTS_HISTORY}
  render={(props) =>
    isSignedIn ? <PointsTransactions /> : <Redirect to={ROUTES.LOGIN} />
  }
></Route>

因此,为了解决这个问题,我只是创建了一个新类型,其中只包含我的用例所需的参数.

Therefore, to solve the problem, I just create a new type with only the necessary parameters for my use case.

import React from 'react';

import { useAppContext } from 'containers/App/AppContext';
import { RouteProps, Route, Redirect } from 'react-router-dom';
import { ROUTES } from 'utils/constants';

type PrivateRouteProps = {
  path: RouteProps['path'];
  component: React.ElementType;
};
const PrivateRoute: React.FunctionComponent<PrivateRouteProps> = ({
  component: Component,
  ...routeProps
}) => {
  const { isSignedIn } = useAppContext();
  return (
    <Route
      {...routeProps}
      render={(props) =>
        isSignedIn ? <Component /> : <Redirect to={ROUTES.LOGIN} />
      }
    />
  );
};

export default PrivateRoute;

这篇关于使用 Typescript 和 React 在私有路由中传递组件道具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆