오늘은 react-route v6 을 사용하면서 리액트로 페이지를 구성하는 도중 로그인을 해야지만 접근 가능한 페이지와 로그인을 하지 않아도 접근 가능한 페이지를 어떻게하면 효율적으로 만들 수 있을지에 대한 여러가지 정보를 구글링 해보고 제일 효율적인 정보를 포스트해 보도록 하겠습니다.
💡 이 글은
react와react-router v6에 대한 기본적인 지식이 있어야 이해하기 쉽습니다.
이 포스트는 code sandbox 에서 확인하실 수 있습니다. 포스트 제일 아래 공유해놓았으니 확인하시면 감사하겠습니다.
Protected route(보호된 경로)는 주로 웹 애플리케이션에서 사용자가 로그인한 상태인지 확인하고, 로그인하지 않은 경우에는 특정 페이지에 접근하는 것을 방지하는 데 사용되는 개념입니다. 이는 일반적으로 사용자의 인증 상태를 확인하여 보호되어야 하는 페이지에 접근하는 데 사용됩니다.
npx create-react-app my-protected-route --template typescript
npm install react-router-dom
환경 세팅은 위의 코드처럼 간단하게 CRA로 리액트 타입스크립트 프로젝트를 생성하고 공식 문서에 나온 react-router-dom을 설치 합니다.
그리고 우리는 routes 파일을 따로 관리할 것이기 때문에 rotes 라는 파일을 생성합니다.

위와 같은 그림으로 폴더 구조를 작성하시면 됩니다.
기본페이지는 / 경로의 홈페이지, 로그인 했을 때 접근이 가능한 privatePage와 페이지, 로그인 없이 접근 가능한 publicPage로 간단하게 구성하겠습니다.
import React from "react";
import ReactDOM from "react-dom/client";
import Routes from "./routes";
const rootElement = document.getElementById("root")!;
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<Routes />
</React.StrictMode>
);
index.tsx 파일에는 우리가 사용할 루트들이 들어간 컴포넌트인 Routes.tsx를 불러와서 사용합니다.
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from "./App";
const router = createBrowserRouter([
{
path: "/",
element: <App />,
},
]);
const Routes = () => {
return <RouterProvider router={router} />;
};
export default Routes;
Routes.tsx 파일에는 우리가 사용할 페이지를 구성합니다. 위의 코드와 같이 지금은 간단하게 홈페이지를 구성할 App.tsx 컴포넌트를 구성해 놓았습니다.
import { Outlet, useNavigate } from "react-router-dom";
import "./styles.css";
export default function App() {
const nav = useNavigate();
const handleClick = (path: string) => {
nav(path);
};
return (
<div className="App">
Home
<div
style={{
display: "flex",
gap: "8px",
margin: "8px auto",
justifyContent: "center",
cursor: "pointer",
}}
>
<button
style={{
backgroundColor: "green",
padding: "10px 16px",
color: "white",
border: "none",
borderRadius: "5px",
cursor: "pointer",
}}
onClick={() => handleClick("public")}
>
Public Page
</button>
<button
style={{
backgroundColor: "red",
padding: "10px 16px",
color: "white",
border: "none",
borderRadius: "5px",
cursor: "pointer",
}}
onClick={() => handleClick("private")}
>
Private Page
</button>
</div>
<Outlet />
</div>
);
}
App.tsx 파일은 홈페이지로, public 페이지와 private 페이지를 갈 수 있는 버튼이 있고, useNavigate를 이용하여 페이지를 이동할 수 있게 구성하였습니다.
publicPage와 privatePage는 여러분들이 마음대로 구성하시면 됩니다. 저는 그냥 pages 폴더에 publicPage와 privatePage 컴포넌트를 만들었습니다.

위와 같이 작동하면 성공입니다.
이제 본격적으로 Protected Route를 만들어 보겠습니다. 우리가 수정해야 할 파일은 routes.tsx 이 한개의 파일과 protectedRoutes 라는 컴포넌트파일을 새로 만들면 됩니다.
import {
createBrowserRouter,
RouteObject,
RouterProvider,
} from "react-router-dom";
import App from "./App";
import PublicPage from "./pages/publicPage";
import PrivatePage from "./pages/privatePage";
import ProtectedRoute from "./protectedRoute";
const Routes = () => {
const userInfo = false; // true or false or localstorage get or redux get
const routes: RouteObject[] = [
{
path: "/",
element: <App />,
children: [
{
path: "/public",
element: <PublicPage />,
},
{
path: "/private",
element: <ProtectedRoute userInfo={userInfo} />,
children: [{ path: "/private", element: <PrivatePage /> }],
},
],
},
];
const router = createBrowserRouter([...routes]);
return <RouterProvider router={router} />;
};
export default Routes;
위의 코드에서 userInfo는 유저의 정보로 유저가 존재하거나 인증된 유저가 있을 경우 boolean값으로 나타냈습니다.
그리고 새로운 routes 변수는 react-route-dom 의 RouteObject 으로 router 경로를 나타냅니다. private 경로에서 새롭게 추가된 ProtectedRoute 컴포넌트 페이지를 부모로 두었고 유저 정보를 props로 전달하였습니다.
마지막으로 router 변수의 createBrowserRouter 에 템플릿 리터럴로 routes 변수를 전달하게 되는데 이렇게 한 이유는 상황에 따라 ...AllRoute, ...AfterLoginRoutes, ...BeforeLoginRoutes등 다양한 경로를 선택하여 넣을 수 있기 때문입니다.
import { Navigate, Outlet } from "react-router-dom";
interface ProtectedRouteProps {
userInfo: boolean;
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ userInfo }) => {
if (!userInfo) {
// 유저 정보가 없다면 홈으로! 혹은 로그인페이지로 가게 할 수 있음
return <Navigate to="/" replace={true} />;
}
// 유저 정보가 있다면 자식 컴포넌트를 보여줌
return <Outlet />;
};
export default ProtectedRoute;
protectedRoute.tsx 파일은 props로 전달받은 유저 정보와 react-router-dom 에서 제공하는 Navigate 컴포넌트를 활용하여 유저 정보가 있지 않을 경우 원하는 경로로 사용자를 이동시킬 수 있습니다. 만약 인증 정보를 가지고 있다면 자식 컴포넌트를 보여줌으로써 인증된 페이지를 보여줄 수 있습니다.
아래의 결과 화면을 보면 더욱 잘 이해하실 수 있습니다.


react-router-dom으로 경로를 보호하는 방법은 많은 방법이 있겠지만 최대한 간결하고 유지보수하기 쉽게 작성하는 방법으로 위의 방법이 적합하다고 생각합니다.
하지만 위의 방법은 경로 보호의 한 가지 간결한 예시로 봐주셨으면 좋겠고, 프로젝트의 특정 요구사항에 따라 다양한 방식으로 구현될 수 있습니다. 프로젝트 특성에 맞게 상황에 따라 적절한 방법을 선택하고 확장해 나가시면 좋을 것 같습니다.
이상으로 글을 마치겠습니다. 모두 Happy Coding! 하시길 바랍니다.