글모음

[ React Router V6 ] - PrivateRouter 알아보기 (Outlet) 본문

프로그래밍 공부/React

[ React Router V6 ] - PrivateRouter 알아보기 (Outlet)

Nova_61 2023. 3. 20. 09:39
728x90
반응형

 

 

PrivateRouter

리액트에서 웹 애플리케이션을 개발할 때, 인증된 사용자만 특정 경로에 접근할 수 있도록 제한하려면 어떻게 해야 할까?

React Router의 'PrivateRoute' 컴포넌트를 이용하여 인증이 필요한 경로에 대한 접근을 제한하는 법을 정리하고

이전 버전(v5)과 현재 버전(v6)의 'PrivateRoute' 컴포넌트를 비교해 보자


 

[ PrivateRoute란? ]

PrivateRoute는 사용자가 인증(로그인)이 되어 있을 때에만 특정 페이지에 접근할 수 있게 하는 기능을 제공한다.

인증(로그인)되지 않은 사용자가 내 정보 페이지나 대시보드 페이지와 같은 페이지에 PrivateRoute로 설정된 페이지로 접근하려 하면, 지정된 페이지로(Home이나 Login) 리다이렉트 돼서 사용자가 인증을 받지 못하면 접근하지 못하도록 막아준다.

 

쉽게 말해, 네이버 쇼핑 같은 서비스에서 로그인이 되지 않은 상태로 결제하려 하면 로그인 페이지로 리다이렉트 되는 걸 생각하면 된다.

 

React Router V6에서는 간단하고 깔끔한 방식으로 PrivateRoute를 구현할 수 있게 달라졌는데 V5와 V6의 차이에 대해 정리하려고 한다.

 

 


< V5의 PrivateRouter 예시 - 이전 버전 > 

이 코드를 현재 버전의 Router에서 코드를 돌리면 에러가 뜬다^^

 

- 에러 

[Error] Error: [PrivateRoute] is not a <Route> component.
All component children of <Routes> must be a <Route> or <React.Fragment>

 

-> '<Routes> 내부에 있는 모든 컴포넌트들은 <Route> 또는 <React.Fragment> 여야 한다.' 

 

<PrivateRoute> 컴포넌트를 <Route>로 변경하라는 소리인데 그러면 PrivateRoute를 못쓰는 거 아닌가!! 하고 머리가 순간 복잡해졌다.


< V5(이전) 버전 PrivateRouter >

검색해 본 결과, <PrivateRoute> 컴포넌트를 <Route>로 변경하라는 말이 맞았다.

React Router의 현재 버전에서는 App.js에서 Route 설정부터, PrivateRoute 컴포넌트 생성부터 다 달라졌다.

 

1. PrivateRoute 컴포넌트 생성

인증된 사용자만 액세스 할 수 있는 개인 경로를 만드는 데 사용되는 PrivateRoute 컴포넌트를 만들어줘야 한다.

// src/components/PrivateRoute.tsx
import React, { useContext } from "react";
import { Route, Navigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";

interface PrivateRouteProps {
  path: string;
  element: React.ReactElement;
}

const PrivateRoute: React.FC<PrivateRouteProps> = ({ path, element }) => {
  const { state : AuthState } = useContext(AuthContext);

  return AuthState.isLoggedIn ? (
    <Route path={path} element={element} />
  ) : (
    <Navigate to="/login" />
  );
};

export default PrivateRoute;


PrivateRoute 컴포넌트는 path와 element 두 개의 props를 받는다.

1. path : 이동하고 싶은 페이지 경로

2. element는 해당 경로에서 렌더링 할 React 요소

useContext를 사용하여 AuthContext로부터 현재 인증 상태를 가져와서 AuthState.isLoggedIn을 통해 사용자가 로그인되어 있는지 확인하고, 사용자가 로그인되어 있다면 Route 요소를 렌더링 하고, 그렇지 않으면 사용자를 로그인 페이지로 리디렉션 한다.

 

2. PrivateRoute 컴포넌트 라우트 설정

// src/App.tsx

import React, { useContext, useReducer } from "react";
import { Route, Routes } from "react-router-dom";

// 상태관리를 위한 AuthContext
import { AuthContext, authReducer, initialState } from "./context/AuthContext";

/* page components들 생략 */

import PrivateRoute from "./utils/PrivateRoute";

export function App() {
  const [authState, dispatch] = useReducer(authReducer, initialState);

  return (
    <AuthContext.Provider value={{ state: authState, dispatch }}>      
     <Routes>
        <Route path="/" element={<Landing />} />
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<SignUp />} />
        <Route path="*" element={<NotFound />} />
        
        // PrivateRoute로 설정해준다
        <PrivateRoute path="/dashboard:id" element={<Dashboard />} />
        <PrivateRoute path="/profile:id" element={<Profile />} />
        
      </Routes>
    </AuthContext.Provider>
  );
}

export default App;

인증이 필요한 페이지에 Route 대신 PrivateRoute 설정을 해주면 된다.

이게 V5에서의 PrivateRoute 설정이다.


< 변경된 현재 버전 PrivateRouter >

 

1. PrivateRoutes 컴포넌트 생성

React Router V6에서는 <Outlet>이라는 새로운 컴포넌트를 사용하는데, 

<Outlet> 컴포넌트는 부모 <Route> 요소 내에서 자식 요소를 렌더링 하는 데 사용된다.

// src/context/AuthContext.tsx

import React, { useContext } from "react";
import { Outlet, Navigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";

const PrivateRoutes: React.FC = () => {
  const { state: authState } = useContext(AuthContext);

// 반드시 <Outlet />을 써야한다.
  return authState.isLoggedIn ? <Outlet /> : <Navigate to="/login" />;
};

export default PrivateRoutes;

<PrivateRoutes> 컴포넌트 내부에서는  authState의 isLoggedIn으로 인증 여부를 확인하고, 인증되지 않은 사용자의 경우에는 <Navigate> 컴포넌트를 사용해 원하는 페이지로 리다이렉트 해주는 로직을 구현하면 된다. 

나 같은 경우에는 인증되지 않은 사용자인 경우에는 login 페이지로 리다이렉트 하도록 만들었다.

 

2. PrivateRoutes 컴포넌트 라우트 설정

 

기존의 <Route> 요소에 기능을 추가하는 대신, <Route element> props로 <PrivateRoutes>를 구성해 주고, 하위 component 안에는 PrivateRoute를 적용을 해야 할 Route끼리 묶어서 PrivateRoutes 컴포넌트 안에 모아줘야 한다.

// src/App.tsx

import React, { useContext, useReducer } from "react";
import { Route, Routes } from "react-router-dom";

// 상태관리를 위한 AuthContext
import { AuthContext, authReducer, initialState } from "./context/AuthContext";

/* page components들 생략 */

import PrivateRoutes from "./utils/PrivateRoutes";

export function App() {
  const [authState, dispatch] = useReducer(authReducer, initialState);

  return (
    <AuthContext.Provider value={{ state: authState, dispatch }}>
      <Routes>
        <Route path="/" element={<Landing />} />
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<SignUp />} />
        <Route path="*" element={<NotFound />} />

        // PrivateRoutes를 적용해야할 Route 끼리 모아줘야 한다.
        <Route element={<PrivateRoutes />}>
          <Route path="/dashboard:id" element={<Dashboard />} />
          <Route path="/profile:id" element={<Profile />} />
        </Route>
        
      </Routes>
    </AuthContext.Provider>
  );
}

export default App;

 

이전버전(V5)에서는 하나하나 'PrivateRoute' 설정해 준 것과 다르게 현재 버전(V6)에서는 'PrivateRoutes' component안에 접근을 막고 싶은 Route들을 넣는다. 사소하지만 V5에서는 개별적이라 'PrivateRoute'라고 하고, V6에서는 'PrivateRoutes'라고 하는 거에 주의하자

 

3. 결과 확인

 

이전 버전에 비하면 비교적 코드가 간결해졌지만 새로 바뀐 지 얼마 지나지 않아서 옛날 자료들이 대부분이라 머리가 복잡했었다.

잘못된 정보나 이전 버전의 정보가 있을 수도 있으니 항상 버전 확인하고 코드를 짜야겠다..

특히나 React Router는 버전이 달라질 때마다 은근 뭐가 많이 바뀌는듯하다.

 

 

728x90
반응형

'프로그래밍 공부 > React' 카테고리의 다른 글

React 공부 자료 모음  (0) 2021.05.27
Comments