【问题标题】:Pass component props in Private Route with Typescript and React使用 Typescript 和 React 在 Private Route 中传递组件道具
【发布时间】:2020-12-07 08:04:28
【问题描述】:

我正在使用来自 React Router v4 的 Route 组件的渲染道具,使用 Typescript 和 React 实现 Authenticated Routes。

路线:

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 都会抛出以下错误。

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

Image of the error

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

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

谢谢!

【问题讨论】:

  • 您使用的是react@types/react 的哪个版本?
  • 嗨,我正在使用React 16.13.1@types/react 16.9.41
  • 由于我没有看到您的代码有任何问题,所以您能否分享您的堆栈跟踪,以显示错误来自何处?
  • 我用实际错误的图片更新了帖子。
  • 别担心,如果我没有找到解决方案,我稍后会添加一个简单的 repo。谢谢!

标签: reactjs typescript react-router


【解决方案1】:

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

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)。

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

因此,为了解决这个问题,我只需要为我的用例创建一个只包含必要参数的新类型。

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;

【讨论】:

    猜你喜欢
    • 2021-09-08
    • 2021-04-01
    • 2020-08-20
    • 2020-01-25
    • 2017-05-16
    • 2021-02-23
    • 2019-04-01
    • 2018-08-22
    • 1970-01-01
    相关资源
    最近更新 更多