React - Router
◆ BrowserRouter와 createBrowserRouter
React로 여러 페이지를 구성하다 보면 다음과 같은 URL이 필요해진다.
/
/about
/services
/notice
/contact
React에서는 실제로 여러 HTML 파일을 만드는 대신, React Router를 이용하여 URL에 따라 다른 컴포넌트를 화면에 보여줄 수 있다.
React Router에서 라우팅을 구성하는 방법 중 자주 사용되는 방식이 바로
BrowserRoutercreateBrowserRouter
이다.
둘 다 React 애플리케이션에서 URL에 따라 화면을 전환하기 위해 사용하지만, 라우팅을 구성하는 방식에는 차이가 있다.
◆ 먼저 라우팅(Routing)이란?
라우팅은 쉽게 말하면
“현재 URL에 어떤 화면을 보여줄 것인가?”
를 결정하는 것이다.
예를 들어 다음과 같은 규칙을 만들 수 있다.
| URL | 화면 |
|---|---|
/ |
HomePage |
/about |
AboutPage |
/services |
ServicesPage |
/notice |
NoticePage |
사용자가 /about으로 이동하면 AboutPage를 보여주고, /notice로 이동하면 NoticePage를 보여주는 것이다.
이러한 URL과 컴포넌트의 연결을 관리하는 것이 React Router이다.
◆ BrowserRouter
먼저 BrowserRouter 방식부터 살펴보자.
가장 기본적인 형태는 다음과 같다.
import { BrowserRouter, Routes, Route } from 'react-router-dom'
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/services" element={<ServicesPage />} />
</Routes>
</BrowserRouter>
)
}
이 코드를 쉽게 해석하면 다음과 같다.
BrowserRouter
↓
현재 URL 확인
↓
Routes
↓
URL과 일치하는 Route 찾기
↓
해당 컴포넌트 보여주기
예를 들어 사용자가
/about
으로 이동하면
<Route path="/about" element={<AboutPage />} />
가 선택되어 AboutPage가 화면에 표시된다.
◆ BrowserRouter 방식의 특징
BrowserRouter 방식에서는 라우팅을 주로 JSX 안에서 작성한다.
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/services" element={<ServicesPage />} />
</Routes>
따라서 구조를 처음 배우는 입장에서는 비교적 직관적이다.
| URL | 컴포넌트 |
|---|---|
/ |
HomePage |
/about |
AboutPage |
/services |
ServicesPage |
처럼 바로 확인할 수 있기 때문이다.
◆ createBrowserRouter
createBrowserRouter는 라우팅 설정을 별도의 Router 객체로 만드는 방식이다.
예를 들어 다음과 같이 작성할 수 있다.
import { createBrowserRouter } from 'react-router-dom'
export const router = createBrowserRouter([
{
path: '/',
element: <HomePage />,
},
{
path: '/about',
element: <AboutPage />,
},
{
path: '/services',
element: <ServicesPage />,
},
])
그리고 만들어진 router를 RouterProvider에 전달한다.
import { RouterProvider } from 'react-router-dom'
import { router } from './app/router'
createRoot(document.getElementById('root')!).render(
<RouterProvider router={router} />
)
전체적인 구조는 다음과 같다.
createBrowserRouter()
↓
라우팅 설정 생성
↓
router
↓
RouterProvider
↓
React 애플리케이션에 적용
◆ BrowserRouter와 createBrowserRouter의 가장 큰 차이
두 방식을 가장 간단하게 비교하면 다음과 같다.
| 구분 | BrowserRouter | createBrowserRouter |
|---|---|---|
| 라우팅 작성 방식 | JSX | Router 객체 |
| 사용 방법 | BrowserRouter + Routes + Route | createBrowserRouter + RouterProvider |
| 라우팅 설정 | 컴포넌트 내부 | 별도의 설정으로 분리 가능 |
| 중첩 라우팅 | 가능 | 가능 |
| 동적 URL | 가능 | 가능 |
| Data Router 기능 | 제한적 | 지원 |
| 복잡한 프로젝트 | 관리 방식에 따라 복잡해질 수 있음 | 라우팅 설정을 분리하기 편함 |
| TypeScript 전용인가? | 아니오 | 아니오 |
여기서 가장 중요한 부분은 마지막이다.
createBrowserRouter는 TypeScript를 사용하기 때문에 사용하는 것이 아니다.
JavaScript에서도 사용할 수 있고 TypeScript에서도 사용할 수 있다.
즉,
TypeScript
↓
프로그래밍 언어 및 타입 시스템
BrowserRouter
createBrowserRouter
↓
React Router의 라우팅 구성 방식
으로 서로 다른 개념이다.
◆ 두 방식의 구조를 비교해보자
1. BrowserRouter 방식
보통 다음과 같은 구조가 된다.
main.tsx
↓
App.tsx
↓
BrowserRouter
↓
Routes
↓
Route
↓
Page
예를 들어 App.tsx에서:
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
</Routes>
</BrowserRouter>
)
}
처럼 작성한다.
2. createBrowserRouter 방식
반면 createBrowserRouter를 사용하면 다음과 같이 구성할 수 있다.
main.tsx
↓
RouterProvider
↓
router.tsx
↓
createBrowserRouter()
↓
Page
예를 들어:
router.tsx
export const router = createBrowserRouter([
{
path: '/',
element: <HomePage />,
},
{
path: '/about',
element: <AboutPage />,
},
])
main.tsx
createRoot(document.getElementById('root')!).render(
<RouterProvider router={router} />
)
즉 라우팅 설정을 router.tsx라는 별도의 파일로 분리할 수 있다.
◆ createBrowserRouter의 장점
createBrowserRouter의 장점은 단순히 라우팅 설정을 분리할 수 있다는 것만은 아니다.
React Router의 Data Router 기능을 함께 사용할 수 있다는 것이 중요한 차이점이다.
예를 들어 특정 페이지를 보여주기 전에 데이터를 가져오는 loader를 라우트에 연결할 수 있다.
const router = createBrowserRouter([
{
path: '/notice',
element: <NoticePage />,
loader: async () => {
// 게시글 데이터 가져오기
return getNoticeList()
},
},
])
이렇게 라우트 자체에 데이터 로딩과 같은 기능을 연결할 수 있다.
또한 action을 이용하여 폼 제출 등의 라우트 관련 작업도 구성할 수 있다.
즉 createBrowserRouter는 단순히
URL → 컴포넌트
만 연결하는 것이 아니라,
URL
↓
라우트
↓
데이터 로딩
↓
컴포넌트
와 같은 구조로 애플리케이션의 라우팅과 데이터 처리를 함께 관리하기 좋은 방식이다.
◆ 중첩 라우팅도 쉽게 구성할 수 있다
createBrowserRouter에서는 children을 이용하여 부모와 자식 라우트를 구성할 수 있다.
예를 들어:
const router = createBrowserRouter([
{
path: '/',
element: <PublicLayout />,
children: [
{
index: true,
element: <HomePage />,
},
{
path: 'about',
element: <AboutPage />,
},
{
path: 'services',
element: <ServicesPage />,
},
],
},
])
이 구조는 다음과 같다.
/
└── PublicLayout
├── /
│ └── HomePage
│
├── /about
│ └── AboutPage
│
└── /services
└── ServicesPage
여기서 PublicLayout은 공통 레이아웃 역할을 한다.
예를 들어:
┌─────────────────────────────┐
│ Header │
├─────────────────────────────┤
│ │
│ <Outlet /> │
│ │
├─────────────────────────────┤
│ Footer │
└─────────────────────────────┘
<Outlet /> 부분에 현재 URL에 해당하는 자식 페이지가 들어간다.
/about이라면:
PublicLayout
├── Header
├── AboutPage
└── Footer
가 되고, /services라면:
PublicLayout
├── Header
├── ServicesPage
└── Footer
가 된다.
이것을 Nested Routing(중첩 라우팅)이라고 한다.
◆ 실제 프로젝트에서는 어떻게 사용할까?
예를 들어 일반 사용자 페이지와 관리자 페이지가 함께 있는 프로젝트라고 생각해보자.
/
├── /about
├── /services
├── /notice
└── /contact
/portal/admin/login
/portal/admin
/portal/admin/hotels
/portal/admin/posts
이런 구조라면 createBrowserRouter를 이용하여 라우팅 설정을 한 곳에서 관리할 수 있다.
export const router = createBrowserRouter([
{
path: '/',
element: <PublicLayout />,
children: [
{ index: true, element: <HomePage /> },
{ path: 'about', element: <AboutPage /> },
{ path: 'services', element: <ServicesPage /> },
{ path: 'notice', element: <NoticePage /> },
],
},
{
path: '/portal/admin/login',
element: <LoginPage />,
},
{
path: '/portal/admin',
element: (
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
),
},
{
path: '/portal/admin/posts',
element: (
<ProtectedRoute>
<PostManagePage />
</ProtectedRoute>
),
},
])
이렇게 하면 라우팅 구조를 한눈에 확인할 수 있다.
Router
│
├── Public
│ └── PublicLayout
│ ├── Home
│ ├── About
│ ├── Services
│ └── Notice
│
├── Admin Login
│ └── LoginPage
│
└── Admin
└── ProtectedRoute
├── Dashboard
└── Posts
특히 관리자 페이지처럼 인증 여부를 확인해야 하는 화면에서는 ProtectedRoute와 조합하여 구조를 명확하게 만들 수 있다.
◆ 그렇다면 어떤 것을 사용해야 할까?
둘 중 하나가 무조건 더 좋은 것은 아니다.
간단한 프로젝트라면 다음처럼 BrowserRouter를 사용하는 것도 충분하다.
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
</Routes>
</BrowserRouter>
반면 다음과 같은 기능이 많아진다면 createBrowserRouter 방식이 편리할 수 있다.
- ✓ 많은 페이지
- ✓ 중첩 라우팅
- ✓ 공통 Layout
- ✓ 관리자 페이지
- ✓ 인증 처리
- ✓ loader
- ✓ action
- ✓ 라우팅 설정을 별도 파일로 관리
댓글남기기