리액트 스터디 6주차 - react-router-dom 기본 사용법

Nomore·2025년 10월 14일

ReactStudy

목록 보기
7/7

1) 폴더 구조(아주 심플)

src/
 ├─ main.jsx
 ├─ App.jsx
 ├─ pages/
 │   ├─ Home.jsx
 │   ├─ Products.jsx
 │   └─ ProductDetail.jsx
 └─ data/
     └─ products.js
  • Home: 첫 화면
  • Products: 목록
  • ProductDetail: /products/:id 상세
  • products.js: 더미 데이터/헬퍼

2) 라우터 진입: BrowserRouter

앱의 최상단BrowserRouter를 한 번만 감싼다.

// src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App.jsx'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
)

3) 라우트 테이블: Routes / Route

경로와 컴포넌트를 1:1로 이어준다.
여기서는 / (홈), /products (목록), /products/:id (상세) 3가지만 둔다.

// src/App.jsx
import { Routes, Route, Link } from 'react-router-dom'
import Home from './pages/Home.jsx'
import Products from './pages/Products.jsx'
import ProductDetail from './pages/ProductDetail.jsx'

export default function App() {
  const navStyle = { display: 'flex', gap: 12, padding: 16, borderBottom: '1px solid #eee' }

  return (
    <>
      <nav style={navStyle}>
        <Link to="/">Home</Link>
        <Link to="/products">Products</Link>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="products" element={<Products />} />
        {/* /products/:id → 상세 */}
        <Route path="products/:id" element={<ProductDetail />} />
        {/* 404 */}
        <Route path="*" element={<div style={{ padding: 24 }}>페이지를 찾을 수 없습니다.</div>} />
      </Routes>
    </>
  )
}

4) 더미 데이터

실무에선 API를 부르겠지만, 흐름만 보려면 배열로 충분하다.

// src/data/products.js
export const products = [
  { id: 'p-100', name: 'Air Runner', price: 129000, description: '가벼운 데일리 러닝화' },
  { id: 'p-101', name: 'Trail Master', price: 159000, description: '접지력 좋은 트레일화' },
  { id: 'p-102', name: 'City Walk',  price:  99000, description: '일상용 워킹화' }
]

export function getProductById(id) {
  return products.find(p => p.id === id) || null
}

5) 페이지 컴포넌트

// src/pages/Home.jsx
export default function Home() {
  return (
    <section style={{ padding: 24 }}>
      <h1></h1>
      <p>리액트 라우터(v6+) 기본 사용법과 상품 상세 라우팅을 연습합니다.</p>
    </section>
  )
}

목록

Link/products/:id에 진입한다.

// src/pages/Products.jsx
import { Link } from 'react-router-dom'
import { products } from '../data/products.js'

export default function Products() {
  return (
    <section style={{ padding: 24 }}>
      <h1>상품 목록</h1>
      <ul style={{ marginTop: 16, display: 'grid', gap: 12 }}>
        {products.map(p => (
          <li key={p.id} style={{ border: '1px solid #eee', borderRadius: 8, padding: 16 }}>
            <h3 style={{ margin: '0 0 8px' }}>{p.name}</h3>
            <p style={{ margin: '0 0 8px', color: '#666' }}>{p.description}</p>
            <strong>{p.price.toLocaleString()}</strong>
            <div style={{ marginTop: 12 }}>
              <Link to={`/products/${p.id}`}>자세히 보기</Link>
            </div>
          </li>
        ))}
      </ul>
    </section>
  )
}

상세

핵심은 useParams()URL 파라미터를 읽는 것.
없으면 404 대체 UI를 보여주고, 있으면 해당 상품을 렌더링한다.

// src/pages/ProductDetail.jsx
import { useParams, useNavigate } from 'react-router-dom'
import { getProductById } from '../data/products.js'

export default function ProductDetail() {
  const { id } = useParams()
  const navigate = useNavigate()

  const product = id ? getProductById(id) : null

  if (!product) {
    return (
      <section style={{ padding: 24 }}>
        <h1>상품을 찾을 수 없습니다.</h1>
        <p style={{ color: '#666' }}>잘못된 주소이거나 삭제된 상품일 수 있습니다.</p>
        <button onClick={() => navigate(-1)} style={{ marginTop: 12 }}>뒤로 가기</button>
      </section>
    )
  }

  return (
    <section style={{ padding: 24 }}>
      <button onClick={() => navigate(-1)} style={{ marginBottom: 12 }}>← 목록으로</button>
      <h1>{product.name}</h1>
      <p style={{ color: '#666', margin: '8px 0 16px' }}>{product.description}</p>
      <strong style={{ fontSize: 18 }}>{product.price.toLocaleString()}</strong>
      <div style={{ marginTop: 16 }}>
        <button onClick={() => alert('장바구니 담기(예시)')}>장바구니</button>
      </div>
    </section>
  )
}

6) 여기까지 정리

  • 한 번 감싸기: 앱 루트에 BrowserRouter
  • 경로 매핑: <Routes><Route path="..." element={...} /></Routes>
  • 상세 파라미터: useParams():id 읽기
  • 이동 제어: Link로 화면 전환, useNavigate()로 뒤로가기/특정 경로 이동
  • 간단한 404: path="*"로 대체 UI

중요한 건 “복잡하게 시작하지 않기”. 지금 구조에 쿼리스트링(useSearchParams), 보호 라우트(로그인 후 접근), 코드 스플리팅(React.lazy/Suspense) 등을 천천히 얹어가면 된다.
기본기가 익숙해지면 createBrowserRouter(데이터 라우터)로 로더/액션/에러 경로를 통합하는 방식도 자연스럽게 이해된다.

0개의 댓글