programing

TypeScript 및 React-Router 4, 5, 또는 6을 사용하여 보호된 경로 또는 개인 경로를 다시 작성하려면 어떻게 해야 합니까?

lastmemo 2023. 3. 22. 20:37
반응형

TypeScript 및 React-Router 4, 5, 또는 6을 사용하여 보호된 경로 또는 개인 경로를 다시 작성하려면 어떻게 해야 합니까?

저는 이 웹 사이트를<PrivateRoute>TypeScript를 사용한 리액트 라우터 문서에 설명된 대로입니다.누가 나 좀 도와줄래?

리액트 라우터의 privateRoute 문서:

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{pathname: '/login', state: { from: props.location }
   }}/>
  )
 )}/>
)

다음은 TypeScript 버전입니다(동작하지 않습니다).

const PrivateRoute = (theProps: { path: string, component: React.SFC<RouteComponentProps<any> | undefined> | React.ComponentClass<RouteComponentProps<any> | undefined> }) => {
    return <Route path={theProps.path} render={props => (
        fakeAuth.isAuthenticated ? (
            <React.Component {...theProps} /> <!-- **** It will raise error *** -->
        ) : (
                <Redirect to={{
                    pathname: '/',
                    state: { from: props.location }
                }} />
            )
    )} />
}

<React.Component {...thisProps} />옳지 않아요.오류: NodeInvocation예외: inst.render는 TypeError 함수가 아닙니다.inst.render는 함수가 아닙니다.

오리지널 앤서(2017년)

(다음 답변 갱신)

이 오류는 렌더링의 입력과 암묵적인 반환과 관련이 있을 수 있습니다.이 문제를 해결하면 최종적으로 다음과 같은 문제가 발생합니다.

const PrivateRoute = ({component, isAuthenticated, ...rest}: any) => {
    const routeComponent = (props: any) => (
        isAuthenticated
            ? React.createElement(component, props)
            : <Redirect to={{pathname: '/login'}}/>
    );
    return <Route {...rest} render={routeComponent}/>;
};

이 컴포넌트는 다음과 같이 사용할 수 있습니다.

<PrivateRoute
    path='/private'
    isAuthenticated={this.props.state.session.isAuthenticated}
    component={PrivateContainer}
/>

상기 솔루션에는 몇 가지 인출이 있습니다.그 중 하나는 타입의 안전성을 잃는 것입니다.

아마 그 연장선상에Route컴포넌트가 더 좋습니다.

import * as React from 'react';
import {Redirect, Route, RouteProps} from 'react-router';

export interface ProtectedRouteProps extends RouteProps {
    isAuthenticated: boolean;
    authenticationPath: string;
}

export class ProtectedRoute extends Route<ProtectedRouteProps> {
    public render() {
        let redirectPath: string = '';
        if (!this.props.isAuthenticated) {
            redirectPath = this.props.authenticationPath;
        }

        if (redirectPath) {
            const renderComponent = () => (<Redirect to={{pathname: redirectPath}}/>);
            return <Route {...this.props} component={renderComponent} render={undefined}/>;
        } else {
            return <Route {...this.props}/>;
        }
    }
}

따라서 다음과 같이 컴포넌트를 사용할 수 있습니다.

const defaultProtectedRouteProps: ProtectedRouteProps = {
    isAuthenticated: this.props.state.session.isAuthenticated,
    authenticationPath: '/login',
};

<ProtectedRoute
    {...defaultProtectedRouteProps}
    exact={true}
    path='/'
    component={ProtectedContainer}
/>

갱신(2019년 11월)

기능 컴포넌트를 작성하는 경우에도 매우 유사한 방법으로 작성할 수 있습니다.이것은 React Router 5에서도 동작합니다.

import * as React from 'react';
import { Redirect, Route, RouteProps } from 'react-router';

export interface ProtectedRouteProps extends RouteProps {
  isAuthenticated: boolean;
  isAllowed: boolean;
  restrictedPath: string;
  authenticationPath: string;
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = props => {
  let redirectPath = '';
  if (!props.isAuthenticated) {
    redirectPath = props.authenticationPath;
  }
  if (props.isAuthenticated && !props.isAllowed) {
    redirectPath = props.restrictedPath;
  }

  if (redirectPath) {
    const renderComponent = () => <Redirect to={{ pathname: redirectPath }} />;
    return <Route {...props} component={renderComponent} render={undefined} />;
  } else {
    return <Route {...props} />;
  }
};

export default ProtectedRoute;

갱신(2019년 12월)

사용자를 먼저 액세스하려는 경로로 리디렉션하려면 경로를 기억해야 합니다. 그래야 인증이 성공한 후 리디렉션할 수 있습니다.다음 답변이 그 과정을 안내합니다.

react-router-dom 인증 성공 후 요청된 페이지로 사용자 리다이렉트

갱신(2021년 3월)

위의 해결책은 좀 구식입니다.ProtectedRoute 컴포넌트는 다음과 같이 간단하게 기술할 수 있습니다.

import { Redirect, Route, RouteProps } from 'react-router';

export type ProtectedRouteProps = {
  isAuthenticated: boolean;
  authenticationPath: string;
} & RouteProps;

export default function ProtectedRoute({isAuthenticated, authenticationPath, ...routeProps}: ProtectedRouteProps) {
  if(isAuthenticated) {
    return <Route {...routeProps} />;
  } else {
    return <Redirect to={{ pathname: authenticationPath }} />;
  }
};

리액트 라우터 V6를 사용하는 경우,Redirect와 함께Navigate처음 요청된 페이지로 리다이렉트하는 완전한 예는 다음과 같습니다.

갱신(2022년 1월)

의 자녀로서<Routes>할 필요가 있다<Route>요소<ProtectedRoute>다음 항목으로 변경할 수 있습니다.

export type ProtectedRouteProps = {
  isAuthenticated: boolean;
  authenticationPath: string;
  outlet: JSX.Element;
};

export default function ProtectedRoute({isAuthenticated, authenticationPath, outlet}: ProtectedRouteProps) {
  if(isAuthenticated) {
    return outlet;
  } else {
    return <Navigate to={{ pathname: authenticationPath }} />;
  }
};

<ProtectedRoute>이제 다음과 같이 적용할 수 있습니다.

const defaultProtectedRouteProps: Omit<ProtectedRouteProps, 'outlet'> = {
  isAuthenticated: !!sessionContext.isAuthenticated,
  authenticationPath: '/login',
};

return (
  <div>
    <Routes>
      <Route path='/' element={<Homepage />} />
      <Route path='dashboard' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Dashboard />} />} />
      <Route path='protected' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Protected />} />} />
      <Route path='nested' element={<ProtectedRoute {...defaultProtectedRouteProps} outlet={<Layout />} />}>
        <Route path='one' element={<Protected />} />
        <Route path='two' element={<Protected />} />
      </Route>
      <Route path='login' element={<Login />} />
    </Routes>
  </div>
);

React Router 6의 예도 업데이트했습니다.현재, 이것에 관한 공식 가이드가 있습니다.https://reactrouter.com/docs/en/v6/examples/auth

아직 SFC 양식을 사용할 수 있습니다. 조금 더 깔끔한 것 같습니다.필요한 소품만 있으면 됩니다.RouteProps:

const PrivateRoute: React.SFC<RouteProps> = ({
  component: Component,
  ...rest
}: {
  component: React.ComponentType<RouteProps>;
}) => (
  <Route
    {...rest}
    render={props =>
      fakeAuth.isAuthenticated 
        ? <Component {...props} /> 
        : <Redirect to="/login" />
    }
  />
);

react-router-dom(v6.0.2)의 경우 PrivateRoute 컴포넌트에 다음 코드를 사용할 수 있습니다.

import { FC } from 'react';
import { useAppSelector } from 'app/hooks';
import { Navigate } from 'react-router-dom';

interface PropType {
    component: React.FC;
}

const PrivateRoute: FC<PropType> = ({ component: Component }) => {
    const { isAuthenticated } = useAppSelector(state => state.auth);

    if (isAuthenticated) return <Component />;
    return <Navigate to='/login' />;
};

export default PrivateRoute;

App.tsx 내에서 사용하려면 다음과 같이 사용할 수 있습니다.

        <Routes>
            <Route path='/' element={<LandingPage />} />
            <Route path='/login' element={<LoginPage />} />
            <Route path='/home' element={<PrivateRoute component={HomePage} />} />
            <Route path='*' element={<NotFound />} />
        </Routes>

My Private Route

import React from 'react'
import {Redirect, Route, RouteProps} from 'react-router'

export interface IPrivateRouteProps extends RouteProps {
  isAuth: boolean // is authenticate route
  redirectPath: string // redirect path if don't authenticate route
}

const PrivateRoute: React.FC<IPrivateRouteProps> = (props) => {
   return props.isAuth ? (
    <Route {...props} component={props.component} render={undefined} />
  ) : (
    <Redirect to={{pathname: props.redirectPath}} />
  )
}

export default PrivateRoute

사용.

<PrivateRoute isAuth={false} redirectPath="/login" path="/t1">
  <Pages.Profile /> your`s protected page
</PrivateRoute>

이것은 나에게 큰 도움이 되었다.

import * as React from "react";
import { Route } from "react-router-dom";

interface IProps {
    exact?: boolean;
    path: string;
    component: React.ComponentType<any>;
}

const LoggedOutRoute = ({
    component: Component,
    ...otherProps
}: IProps) => (
    <>
        <header>Logged Out Header</header>
        <Route
            render={otherProps => (
                <>
                    <Component {...otherProps} />
                </>
            )}
        />
        <footer>Logged Out Footer</footer>
    </>
);

export default LoggedOutRoute;

출처 : https://medium.com/octopus-wealth/authenticated-routing-with-react-react-router-redux-typescript-677ed49d4bd6

tsx에서 매우 명시적이고 정확한 유형이나 인터페이스를 제공하지 않고 아래와 같이 쓸 수 있습니다.-{ 컴포넌트: 컴포넌트, ...rest}: any-as type 이라고 쓰면 끝입니다.

  export default function PrivateRoute({ component: Component, ...rest }: any) {
      const { currentUser } = useAuth();

      return (
        <Route
          {...rest}
          render={(props) => {
            return currentUser ? (
              <Component {...props} />
            ) : (
              <Redirect to="/login" />
            );
          }}
        ></Route>
      );
    }

React-router-dom의 v6를 사용하여 이 형식으로 보호된 경로를 처리합니다.

Auth 보호 구성 요소 설정

import React from "react";
import { Navigate, useLocation, useNavigate } from "react-router-dom";
import { useAppSelector } from "../../state/hooks";

const ProtectedRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
  const {user} = <Your-State-Provider>// Redux/Context or even in-memory user
  const location = useLocation();
  return !user.isAuthenticated ? (
    <Navigate to={"/login"} state={{ from: location }} replace />
  ) : (
    children
  );
};

export default ProtectedRoute;

가 Basic 조건에 이에서는 Basic이 사용됩니다.<Navigate/>을 사용하다하여 ★★★★★★★★★★★★★★★★★★★★★★★★에 전달합니다.Navigate따라서 로그인 후 사용자가 원하는 페이지로 자동으로 리디렉션됩니다.「 」를 합니다.childrenchildren이치노이 방법의 장점은 렌더링할 요소를 그대로 정리할 수 있다는 것입니다.<ProtectedRoute>{children}</ProtectedRoute>.

보호 경로 사용

import { Fragment } from "react";
import ProtectedRoute from "./components/ProtectedRoute/ProtectedRoute";//Your protected route
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Login from "./pages/Login/Login";
import MainPage from "./pages/MainPage/MainPage";


const App = () => {
  return (
    <Router>
      <Fragment>
        <nav>
          <Link to="/admin" />
        </nav>
        <Routes>
          <Route
            path="/"
            element={
              <ProtectedRoute>
                <MainPage />
              </ProtectedRoute>
            }
          />
          <Route path="/login" element={<Login />} />
        </Routes>
      </Fragment>
    </Router>
  );
};

export default App;

★★★★★★★★★★★★★★★★★★react-router-dom v6 루트 할 수 됩니다.를 '컴포넌트'로 됩니다.이것으로 보호하는 컴포넌트를ProtectedRoute:

 <Route path="/" element={ <ProtectedRoute><Your-Protected-page /></ProtectedRoute>}/>

나에게 효과가 있었던 것을 덧붙이자면:

interface PrivateRouteProps extends RouteProps {
  component: React.FC<RouteProps>;
  path: string;
}

export default function PrivateRoute({
  component: Component,
  path,
}: PrivateRouteProps) {
  return (
    <Route
      path={path}
      render={(props) =>
        localStorage.getItem('user') ? (
          <Component {...props} />
        ) : (
          <Redirect
            to={{ pathname: '/login', state: { from: props.location } }}
          />
        )
      }
    />
  );
}

다음과 같이 사용할 수 있습니다.

<PrivateRoute path="/user/dashboard" component={Dashboard} />

react-router-dom 6.0.0-beta.4는 나에게만 효과가 있었던 것 같습니다.

App.tsx

import { BrowserRouter as Router, Navigate, Route, Routes } from 'react-router-dom';

interface Props {}
export const App: React.FC<Props> = ({}) => {
    const isAuthenticated = true;
    return (
        <Router>
            <Routes>
                <Route path={`/`} element={isAuthenticated ? <AuthenticatedPage /> : <Navigate to={`/auth`} />} />
                <Route path={`/auth`} element={<AuthenticationPage />} />
            </Routes>
        </Router>
    );
};

https://github.com/remix-run/react-router/issues/8033

빠른 코드 조각:

프라이빗 Rote.tsx

import React from 'react'
import { Route, Redirect, RouteProps } from 'react-router-dom'
import { useLogin} from 'hooks'

interface PrivateRouteProps extends RouteProps {
  component: any
}

export const PrivateRoute = (props: PrivateRouteProps) => {
  const { component: Component, ...rest } = props
  const { isLogin} = useLogin() //true/false or something else

  return account ? <Route {...rest} render={props => <Component {...props} />} /> : <Redirect to="/" />
}

App.tsx에서의 사용방법

<Router>
   <Switch>
      <Route exact path="/" component={Home} />
      <Route exact path="/faq" component={Faq} />
      <PrivateRoute exact path="/profile" component={Profile} />
    </Switch>
</Router>

이건 깔끔하고 심플해요.

import React from "react";
import { Route, Redirect, RouteProps } from "react-router-dom";

import { RoutePaths } from "./RoutePaths";

interface Props extends RouteProps {
    isLoggedIn: boolean;
}

const AuthRoute: React.FC<Props> = ({ component: Component, ...rest }) => {
    if (!Component) {
        return null;
    }

    const { isLoggedIn } = rest;

    return (
        <Route
            {...rest}
            render={(props) =>
                isLoggedIn ? (
                    <Component {...props} />
                ) : (
                    <Redirect
                        to={{
                            pathname: RoutePaths.Auth,
                            /**
                             * For redirecting after login.
                             */
                            state: { from: props.location },
                        }}
                    />
                )
            }
        />
    );
};

export default AuthRoute;


언급URL : https://stackoverflow.com/questions/47747754/how-to-rewrite-the-protected-private-route-using-typescript-and-react-router-4

반응형