리액트 라우터 DOM 설치 및 기본 사용법(React Router v6)
싱글 페이지 애플리케이션(SPA)에서 화면 전환과 URL 관리를 담당하는 표준 라이브러리가 react-router-dom입니다. 이 글에서는 설치 → 기본 셋업 → 페이지 이동 → 파라미터/검색쿼리 → 중첩 라우팅 → 404 처리 순서로 핵심만 알아봅니다. (GitHub Pages 배포 시 HashRouter 권장 안내 포함)
1) 설치
npm i react-router-dom
# yarn add react-router-dom
# pnpm add react-router-dom설치 확인:
npm ls react-router-dom
2) 라우터 선택: BrowserRouter vs HashRouter
- BrowserRouter: 일반 서버 환경(리라이트 설정 가능)에서 추천.
- HashRouter: GitHub Pages처럼 서버 리라이트를 못 하는 정적 호스팅에 추천(새로고침 404 방지).
본 글은 GitHub Pages 배포를 고려해 기본 예제는 HashRouter로 진행합니다. 일반 서버면 BrowserRouter로 그대로 바꿔 쓰면 됩니다.
3) 프로젝트 기본 셋업
3-1) 엔트리에서 라우터 감싸기
src/index.js (또는 main.jsx)
import React from "react";
import ReactDOM from "react-dom/client";
import { HashRouter as Router } from "react-router-dom"; // GH Pages면 HashRouter 권장
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<Router>
<App />
</Router>
);3-2) 라우트 매핑
src/App.jsx
import { Routes, Route, Link, NavLink } from "react-router-dom";
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
export default function App() {
return (
<div style={{ padding: 16 }}>
<h1>React Router v6 Demo</h1>
<nav style={{ marginBottom: 12 }}>
{/* NavLink: 활성 라우트에 클래스/스타일 적용 가능 */}
<NavLink to="/" end style={({ isActive }) => ({ fontWeight: isActive ? "bold" : "normal", marginRight: 8 })}>
Home
</NavLink>
<NavLink to="/about" style={({ isActive }) => ({ fontWeight: isActive ? "bold" : "normal" })}>
About
</NavLink>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* 404 */}
<Route path="*" element={<h2>Not Found</h2>} />
</Routes>
</div>
);
}▶ 실행 화면 설명: 상단에 Home/About 링크가 보이고, 각 링크를 클릭하면 굵게(활성) 표시가 바뀌며 본문이 해당 페이지로 전환됩니다. 새로고침해도 해시(URL # 뒤)가 유지되어 동일 화면이 열립니다.
4) 페이지 이동(Navigate)과 파라미터 전달
4-1) 프로그래매틱 네비게이션
useNavigate()로 코드에서 이동할 수 있습니다.
import { useNavigate } from "react-router-dom";
function Login() {
const navigate = useNavigate();
const onSubmit = (e) => {
e.preventDefault();
// 인증 로직...
navigate("/dashboard"); // 성공 시 이동
};
return (
<form onSubmit={onSubmit}>
<button type="submit">로그인</button>
</form>
);
}4-2) URL 파라미터 읽기
:id 같은 동적 세그먼트를 정의하고 useParams()로 읽습니다.
// App.jsx 일부
import { Routes, Route, Link, useParams } from "react-router-dom";
function Users() {
return (
<div>
<h2>Users</h2>
<ul>
<li><Link to="/users/1">User 1</Link></li>
<li><Link to="/users/2">User 2</Link></li>
</ul>
</div>
);
}
function UserDetail() {
const { id } = useParams();
return <h3>User Detail: {id}</h3>;
}
// Routes 매핑
<Routes>
<Route path="/users" element={<Users />} />
<Route path="/users/:id" element={<UserDetail />} />
<Route path="*" element={<h2>Not Found</h2>} />
</Routes>▶ 실행 화면 설명: /users 페이지에서 User 1 또는 2 링크를 누르면 주소가 /users/1, /users/2로 바뀌고 본문에 선택한 사용자 ID가 표시됩니다.
5) 쿼리스트링(검색 파라미터) 다루기
useSearchParams()로 읽기/쓰기.
import { useSearchParams } from "react-router-dom";
function SearchPage() {
const [sp, setSp] = useSearchParams();
const q = sp.get("q") ?? "";
const onChange = (e) => {
setSp({ q: e.target.value }); // 주소창에 ?q=값 갱신
};
return (
<div>
<h2>Search</h2>
<input placeholder="검색어" value={q} onChange={onChange} />
<p>현재 검색어: <strong>{q}</strong></p>
</div>
);
}▶ 실행 화면 설명: 입력값을 바꾸면 주소창의 쿼리스트링(?q=)이 함께 변경되고 새로고침해도 동일 검색어가 유지됩니다.
6) 중첩 라우팅(Nested Routing)
부모 라우트의 공통 레이아웃 아래에서 자식 라우트가 렌더링되도록 구성합니다.
import { Outlet, Link, Routes, Route } from "react-router-dom";
function DashboardLayout() {
return (
<div style={{ display: "grid", gridTemplateColumns: "180px 1fr", gap: 16 }}>
<aside>
<h3>Dashboard</h3>
<ul>
<li><Link to="overview">Overview</Link></li>
<li><Link to="reports">Reports</Link></li>
</ul>
</aside>
<main>
{/* 자식 라우트가 이 위치에 렌더링됨 */}
<Outlet />
</main>
</div>
);
}
function Overview() { return <h2>Overview</h2>; }
function Reports() { return <h2>Reports</h2>; }
// Routes
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<Overview />} /> {/* /dashboard */}
<Route path="overview" element={<Overview />} />
<Route path="reports" element={<Reports />} />
</Route>
<Route path="*" element={<h2>Not Found</h2>} />
</Routes>▶ 실행 화면 설명: 좌측 메뉴(Overview/Reports)를 클릭하면 우측 본문 영역만 바뀌고 URL은 /dashboard/overview, /dashboard/reports 형태로 변경됩니다.
7) 404(와일드카드) 처리
정의되지 않은 경로에는 마지막에 path="*"를 둬서 404 화면을 출력합니다.
<Routes>
{/* ...기존 라우트 */}
<Route path="*" element={<h2>Not Found</h2>} />
</Routes>▶ 실행 화면 설명: 존재하지 않는 주소를 입력하면 “Not Found”가 표시됩니다.
8) GitHub Pages 배포 팁
- HashRouter 사용 시 새로고침 404를 피할 수 있습니다.
package.json의homepage가 설정되어 있으면,gh-pages로 배포 시 정적 파일 경로가 자동 보정됩니다.
자주 만나는 오류와 해결
- 새로고침 시 404: 정적 호스팅이면
HashRouter로 전환하거나, 서버 리라이트 설정 필요. - 링크 클릭해도 화면이 안 바뀜: 라우터로 앱이 감싸졌는지(
<Router></Router>) 확인. - 활성 링크 스타일이 적용 안 됨:
NavLink사용, v6에선activeClassName대신style/className콜백. - 동적 파라미터가 undefined: 경로에
:id를 선언했고useParams()를 동일 트리의 자식에서 호출했는지 확인.
참고 링크
- React Router 공식 문서(v6): https://reactrouter.com/
- Routes/Route 기본: https://reactrouter.com/en/main/components/routes
- useNavigate: https://reactrouter.com/en/main/hooks/use-navigate
- useParams: https://reactrouter.com/en/main/hooks/use-params
- useSearchParams: https://reactrouter.com/en/main/hooks/use-search-params
- NavLink: https://reactrouter.com/en/main/components/nav-link
함께 보면 좋은 게시글
- 리액트 useEffect 사용법: 의존성 배열과 생명주기 이해
- 리액트 useRef 사용법: DOM 제어, input focus, 이전 값 저장하기
- React 이벤트 처리 방법: onClick·onChange·onSubmit 예제
- 리액트 컴포넌트 반복: map과 key로 리스트 렌더링 최적화
- 리액트 state 관리: useState 기본 사용법과 동작 원리
이 글이 도움이 되셨다면 공유 부탁 드립니다.



