React Router 학습 가이드

React Router
입문 → 실무 전체 지도

URL과 React 컴포넌트가 어떻게 연결되는지부터 Route, Link, useNavigate, useParams, Query String, 중첩 Route, Outlet, Data Router, loader까지 한 페이지에서 흐름으로 이해하는 학습용 문서입니다.

URL→ Route 매칭→ Component 렌더링→ Params / Data 사용

1. React Router가 뭐냐?

React 애플리케이션에서 URL에 따라 보여줄 컴포넌트를 결정하는 라우팅 라이브러리입니다.

/ → Home /products → ProductList /products/10 → ProductDetail /cart → Cart /mypage → MyPage
가장 단순하게 보면 URL → React Router → 해당 컴포넌트 렌더링입니다.
<Route
  path="/products"
  element={<ProductList />}
/>

위 코드는 /products 주소가 매칭되면 <ProductList />를 렌더링하라는 뜻입니다.

설치

npm install react-router

기존 프로젝트에서는 react-router-dom에서 import하는 코드도 자주 볼 수 있습니다.

2. BrowserRouter / Routes / Route

BrowserRouter

BrowserRouter는 아래 컴포넌트 트리에서 Router 기능을 사용할 수 있도록 Router 환경을 제공합니다.

import {
  BrowserRouter,
  Routes,
  Route
} from 'react-router'

function App() {
  return (
    <BrowserRouter>
      <Routes>

        <Route
          path="/"
          element={<Home />}
        />

        <Route
          path="/products"
          element={<Products />}
        />

        <Route
          path="/mypage"
          element={<MyPage />}
        />

      </Routes>
    </BrowserRouter>
  )
}
BrowserRouter └─ Routes ├─ Route / ├─ Route /products └─ Route /mypage
path 어떤 URL과 연결할지 지정합니다.
path="/products"
element 해당 URL에서 렌더링할 React element입니다.
element={<Products />}
현재 URL이 바뀌면 React Router가 다시 Route 매칭을 확인하고, 매칭된 element를 렌더링합니다.

5. Dynamic Route와 useParams

상품 상세처럼 ID에 따라 같은 컴포넌트에서 서로 다른 데이터를 보여줄 때 사용합니다.

<Route
  path="/products/:id"
  element={<ProductDetail />}
/>
/products/1 /products/2 /products/10 /products/100 ↓ 모두 /products/:id Route에 매칭

useParams로 URL 값 꺼내기

import { useParams } from 'react-router'

function ProductDetail() {

  const { id } = useParams()

  return (
    <div>
      상품 번호 : {id}
    </div>
  )
}

URL이 /products/100이면 id는 문자열 "100"입니다.

상품 목록 → 상세페이지 전체 흐름

const products = [
  { id: 1, name: '노트북' },
  { id: 2, name: '키보드' },
  { id: 3, name: '마우스' }
]

function ProductList() {
  return (
    <div>
      {products.map(product => (
        <Link
          key={product.id}
          to={`/products/${product.id}`}
        >
          {product.name}
        </Link>
      ))}
    </div>
  )
}
function ProductDetail() {

  const { id } = useParams()

  const product =
    products.find(
      product =>
        product.id === Number(id)
    )

  return (
    <h1>
      {product?.name}
    </h1>
  )
}
키보드 클릭 ↓ /products/2 ↓ /products/:id Route 매칭 ↓ useParams() ↓ id = "2" ↓ products.find(...) ↓ { id: 2, name: "키보드" } ↓ 화면 렌더링

6. Query String — useSearchParams

페이지, 정렬, 검색조건, 필터처럼 화면의 조건을 URL에 표현할 때 많이 사용합니다.

/products?page=2&category=computer
import { useSearchParams } from 'react-router'

function Products() {

  const [searchParams] = useSearchParams()

  const page =
    searchParams.get('page')

  const category =
    searchParams.get('category')

  return (
    <div>
      <p>page: {page}</p>
      <p>category: {category}</p>
    </div>
  )
}
종류예주 용도
Params /products/10 특정 자원 식별
Query String /products?page=2 검색, 정렬, 필터, 페이지 조건

useLocation

import { useLocation } from 'react-router'

function Page() {

  const location = useLocation()

  console.log(location.pathname)
  console.log(location.search)

  return null
}

7. Nested Route와 Outlet

마이페이지처럼 공통 레이아웃은 유지하고 내부 화면만 바뀌는 구조에서 중요합니다.

/mypage /mypage/profile /mypage/orders /mypage/settings
<Route
  path="/mypage"
  element={<MyPageLayout />}
>

  <Route
    index
    element={<MyPageHome />}
  />

  <Route
    path="profile"
    element={<Profile />}
  />

  <Route
    path="orders"
    element={<Orders />}
  />

</Route>

자식 Route의 path="profile"은 부모 경로와 합쳐져 /mypage/profile이 됩니다.

Outlet

import {
  Link,
  Outlet
} from 'react-router'

function MyPageLayout() {

  return (
    <div className="layout">

      <aside>
        <Link to="profile">프로필</Link>
        <Link to="orders">주문내역</Link>
      </aside>

      <main>
        <Outlet />
      </main>

    </div>
  )
}
<Outlet />은 현재 매칭된 자식 Route가 들어가는 자리입니다.
URL: /mypage/profile MyPageLayout 렌더링 ↓ <Outlet /> ↓ <Profile />

8. 404와 Navigate

404 Route

<Route
  path="*"
  element={<NotFound />}
/>

*는 앞에서 매칭되지 않은 나머지 경로를 처리할 때 사용할 수 있습니다.

로그인 보호 Route

import { Navigate } from 'react-router'

function ProtectedRoute({ children }) {

  const isLogin = true

  if (!isLogin) {
    return (
      <Navigate
        to="/login"
        replace
      />
    )
  }

  return children
}
<Route
  path="/mypage"
  element={
    <ProtectedRoute>
      <MyPage />
    </ProtectedRoute>
  }
/>
/mypage 접근 ↓ 로그인 여부 확인 ↙ ↘ 로그인 O 로그인 X ↓ ↓ MyPage /login 이동

navigate로 state 전달

navigate('/complete', {
  state: {
    name: '홍길동',
    productId: 10
  }
})
const location = useLocation()

console.log(location.state)

9. Data Router — createBrowserRouter + loader

React Router는 기본적인 JSX Route 방식 외에 Router 설정을 객체로 만들고 데이터 로딩 기능을 사용하는 방식도 제공합니다.

createBrowserRouter

import {
  createBrowserRouter
} from 'react-router'

const router =
  createBrowserRouter([
    {
      path: '/',
      element: <Home />
    },
    {
      path: '/products',
      element: <Products />
    }
  ])
import { RouterProvider } from 'react-router/dom'

<RouterProvider router={router} />

loader

async function productsLoader() {

  const response =
    await fetch('/api/products')

  return response.json()
}
{
  path: '/products',
  element: <Products />,
  loader: productsLoader
}

useLoaderData

import { useLoaderData } from 'react-router'

function Products() {

  const products =
    useLoaderData()

  return (
    <div>

      {products.map(product => (
        <div key={product.id}>
          {product.name}
        </div>
      ))}

    </div>
  )
}
/products 이동 ↓ Route 매칭 ↓ loader 실행 ↓ API 데이터 요청 ↓ 데이터 반환 ↓ Products 렌더링 ↓ useLoaderData()

Dynamic Route + loader

{
  path: '/products/:id',
  element: <ProductDetail />,
  loader: productLoader
}

async function productLoader({ params }) {

  const response =
    await fetch(
      `/api/products/${params.id}`
    )

  return response.json()
}

10. 실무형 전체 구조

src ├─ pages │ ├─ Home.jsx │ ├─ ProductList.jsx │ ├─ ProductDetail.jsx │ ├─ Cart.jsx │ └─ MyPage.jsx │ ├─ layouts │ └─ Layout.jsx │ ├─ router │ └─ router.jsx │ └─ main.jsx

Layout.jsx

import {
  Link,
  Outlet
} from 'react-router'

export default function Layout() {

  return (
    <>

      <header>

        <Link to="/">
          쇼핑몰
        </Link>

        <nav>
          <Link to="/products">상품</Link>
          <Link to="/cart">장바구니</Link>
          <Link to="/mypage">마이페이지</Link>
        </nav>

      </header>

      <main>
        <Outlet />
      </main>

    </>
  )
}

router.jsx

import {
  createBrowserRouter
} from 'react-router'

export const router =
  createBrowserRouter([

    {
      path: '/',
      element: <Layout />,

      children: [

        {
          index: true,
          element: <Home />
        },

        {
          path: 'products',
          element: <ProductList />
        },

        {
          path: 'products/:id',
          element: <ProductDetail />
        },

        {
          path: 'cart',
          element: <Cart />
        },

        {
          path: 'mypage',
          element: <MyPage />
        },

        {
          path: '*',
          element: <NotFound />
        }

      ]
    }

  ])

main.jsx

import ReactDOM from 'react-dom/client'

import {
  RouterProvider
} from 'react-router/dom'

import {
  router
} from './router/router'

ReactDOM
  .createRoot(
    document.getElementById('root')
  )
  .render(
    <RouterProvider
      router={router}
    />
  )

11. React Router를 보는 핵심 사고방식

React Router는 단순히 "페이지를 이동하는 라이브러리"라기보다 URL을 React UI 상태와 연결하는 시스템이라고 이해하면 훨씬 쉽습니다.
URL │ ├─ pathname │ └─ /products │ ├─ params │ └─ /products/:id │ id = 10 │ └─ searchParams ├─ ?page=2 └─ ?sort=price

학습 순서

1
BrowserRouter
Router 환경 만들기
2
Routes / Route
URL과 컴포넌트 연결
3
Link / NavLink
사용자 페이지 이동
4
useNavigate
JavaScript로 이동
5
useParams / useSearchParams
URL에서 데이터 읽기
6
Nested Route / Outlet
공통 레이아웃 + 자식 화면
7
Navigate / ProtectedRoute
로그인 등의 접근 제어
8
createBrowserRouter / loader
Data Router로 확장

실무 코드 분석 순서

① 현재 URL이 무엇인가? ↓ ② 어떤 Route가 매칭되는가? ↓ ③ 어떤 Component가 렌더링되는가? ↓ ④ :id 같은 params가 있는가? ↓ ⑤ Outlet에 들어가는 자식 Route가 있는가? ↓ ⑥ loader나 데이터 로딩 로직이 있는가?
특히 useParams + Nested Route + Outlet까지 이해하면 React Router 기본 구조를 읽는 힘이 크게 올라갑니다.