टाइपस्क्रिप्ट और रिएक्ट के साथ प्राइवेट रूट में कंपोनेंट प्रॉपर पास करें

Aug 18 2020

मैं 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;

समस्या यह है कि मैं प्रॉम्प्ट पर सेट घटक को कॉल करना चाहता हूं, हालांकि, हर बार जब मैं यह कोशिश करता हूं, तो टाइपस्क्रिप्ट निम्न त्रुटि को फेंकता है।

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

त्रुटि की छवि

कारण यह प्रतीत होता है कि मार्ग के लिए घटक प्रकार एक टाइपस्क्रिप्ट की अपेक्षा नहीं है जैसा कि यहाँ बताया गया है: https://github.com/microsoft/TypeScript/issues/28631, इसलिए मैंने अभी एक कॉपी बनाई है जिसमें एक नया प्रकार (ComponentToRender) है।

क्या इसे लागू करने का एक बेहतर तरीका है? हो सकता है कि रूटप्रोप्स घटक तत्व को ओवरराइट कर रहा हो?

धन्यवाद!

जवाब

juanjo12x Aug 25 2020 at 16:18

मैंने आखिरकार त्रुटि को समझा और इसे हल किया! कुंजी यह थी कि घटक विशेषता और रेंडर फ़ंक्शन को विभिन्न प्रकार-वार संभाला जाता है। उपयोग करके RouteProps, टाइपस्क्रिप्ट कंपाइलर वास्तव में कंपोनेंट टाइप (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;
}

राउट्स फ़ाइल में रेंडर फ़ंक्शन को स्थानांतरित करने और 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;