React Router로 웹페이지 이동 흐름 완전 정복|SPA 라우팅 구현 모든 방법
🚀 React Router로 웹페이지 이동 흐름 완전 정복|SPA에서 라우팅을 구현하는 모든 방법
안녕하세요, 퍼블리셔 노미입니다!
지금까지 우리는 HTML, CSS, JavaScript, API, 인증, 상태관리, 모달까지 프론트엔드 개발의 핵심 흐름을 따라왔습니다.
하지만 여기서 한 가지 빠질 수 없는 주제가 있어요.
바로 **“라우팅(Routing)”** 입니다.
SPA(Single Page Application)에서는 화면 이동을 어떻게 구현할까요?
새로고침 없이 자연스럽게 페이지를 이동하려면 어떤 기술이 필요할까요?
이 글에서는 프론트 개발자가 꼭 알아야 할 SPA와 라우팅 개념부터 React Router 사용법, 실전 코드 구성까지 자세하게 풀어서 정리해드릴게요.
📌 라우팅(Routing)이란?
라우팅이란 사용자가 웹사이트에서 특정 URL로 이동할 때 알맞은 페이지(컴포넌트)를 보여주는 과정을 말합니다.
- 일반 웹사이트: 페이지 이동 시 새로고침 발생
- SPA(Single Page Application): 페이지 새로고침 없이 URL만 변경되고 화면만 전환
→ SPA에서는 라우터(Router)라는 도구가 필요합니다.
🧩 SPA와 라우팅의 차이
구분 | 전통적 웹사이트 | SPA |
---|---|---|
페이지 이동 | 서버로 새 요청 → 새 HTML 문서 반환 | JS로 URL 변경 → 컴포넌트만 교체 |
새로고침 | 필수 | 불필요 |
속도 | 느림 | 빠름 |
UX | 끊김 발생 | 자연스러움 |
🛠 React Router란?
React Router는 SPA에서 URL에 따라 특정 컴포넌트를 렌더링하도록 도와주는 라이브러리입니다.
프론트엔드 프로젝트에서 가장 많이 사용되는 라우팅 솔루션 중 하나예요.
- 경로에 따라 다른 컴포넌트 보여주기
- 중첩 라우트, 동적 라우트 지원
- 네비게이션, 리다이렉트, protected route 처리
📦 설치 방법
npm install react-router-dom
React 프로젝트에 설치 후 바로 사용할 수 있어요.
🚏 기본 사용법 정리
1. BrowserRouter로 감싸기
import { BrowserRouter } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
{/* 라우트 작성 */}
</Routes>
</BrowserRouter>
);
}
2. Routes & Route 설정
import { Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
path
는 URL 경로element
는 보여줄 컴포넌트
🧭 Link 컴포넌트로 페이지 이동
import { Link } from "react-router-dom";
function Navbar() {
return (
<nav>
<Link to="/">홈</Link>
<Link to="/about">소개</Link>
</nav>
);
}
→ a 태그 대신 Link 컴포넌트를 사용해야 새로고침 없이 이동합니다!
🔗 useNavigate로 코드에서 이동
import { useNavigate } from "react-router-dom";
function LoginButton() {
const navigate = useNavigate();
const handleLogin = () => {
// 로그인 성공 후 이동
navigate("/dashboard");
};
return <button onClick={handleLogin}>로그인</button>;
}
→ 버튼 클릭 등 이벤트 안에서 프로그래밍적으로 경로 변경할 수 있어요.
🧩 중첩 라우트(Nested Routes)
function Dashboard() {
return (
<>
<h1>대시보드</h1>
<Outlet />
</>
);
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/dashboard" element={<Dashboard />}>
<Route path="profile" element={<Profile />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- Outlet은 하위 Route를 렌더링하는 자리
- 중첩 URL: `/dashboard/profile`, `/dashboard/settings`
🧳 URL 파라미터와 useParams 사용법
SPA에서는 URL의 일부를 변수처럼 사용할 수 있습니다.
예를 들어, 게시글 상세 페이지를 구현할 때 이런 식으로 사용해요.
라우트 설정
<Route path="/post/:id" element={<PostDetail />} />
useParams로 URL 값 읽기
import { useParams } from "react-router-dom";
function PostDetail() {
const { id } = useParams();
return <h2>게시글 번호: {id}</h2>;
}
:id
처럼 경로에 변수를 걸고useParams()
로 값을 가져올 수 있어요!
🛣️ 쿼리스트링(Query String) 처리하기
URL에 ?키=값
형태로 데이터가 붙는 걸 **쿼리스트링**이라고 합니다.
React Router에서는 useSearchParams를 사용해서 읽고 쓸 수 있어요.
예시
http://localhost:3000/search?keyword=노미
useSearchParams 사용
import { useSearchParams } from "react-router-dom";
function SearchPage() {
const [searchParams, setSearchParams] = useSearchParams();
const keyword = searchParams.get("keyword");
return <h2>검색어: {keyword}</h2>;
}
🏃 리다이렉트(redirect) 처리
로그인 상태에 따라 강제로 다른 페이지로 보내야 할 때가 있어요.
그럴 때 useNavigate()로 리다이렉트를 처리합니다.
import { useNavigate } from "react-router-dom";
function LoginPage() {
const navigate = useNavigate();
const handleSubmit = () => {
// 로그인 완료 후 메인 페이지로 이동
navigate("/");
};
return <button onClick={handleSubmit}>로그인</button>;
}
🛡️ 인증이 필요한 라우트 보호 (Protected Route)
로그인한 사용자만 접근 가능한 페이지를 만들려면 Route Guard를 구현해야 합니다.
ProtectedRoute 컴포넌트 만들기
function ProtectedRoute({ children }) {
const isLogin = !!localStorage.getItem("token");
if (!isLogin) {
return <Navigate to="/login" />;
}
return children;
}
적용 예시
<Route path="/dashboard" element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
} />
→ 로그인 안 한 사용자는 자동으로 /login으로 이동!
📜 Route 구성 깔끔하게 관리하는 법
페이지가 많아질수록 Routes를 깔끔하게 관리하는 게 중요해요.
routes 배열로 관리
const routes = [
{ path: "/", element: <Home /> },
{ path: "/about", element: <About /> },
{ path: "/login", element: <Login /> },
{ path: "/dashboard", element: <ProtectedRoute><Dashboard /></ProtectedRoute> }
];
map으로 Routes 렌더링
<Routes>
{routes.map(({ path, element }) => (
<Route key={path} path={path} element={element} />
))}
</Routes>
→ 관리 편하고, 추후 수정할 때도 깔끔!
🧭 라우팅 설계할 때 고려해야 할 점
- 중첩 구조를 잘 설계하기
- 권한에 따라 접근 제어
- 404 Not Found 페이지 설정
- SEO 최적화 고려 (meta태그 변경 필요)
- URL 규칙 일관성 유지
404 페이지 처리
<Route path="*" element={<NotFound />} />
→ 모든 경로를 커버하는 “catch-all” 패턴
⚡ 프로그램적 네비게이션 고급 테크닉
앞서 useNavigate()
를 배웠지만, 실제 서비스에서는 더 다양한 이동 제어가 필요해요.
특히, replace 옵션을 주면 **히스토리 스택을 새로 덮어쓰기** 때문에 “뒤로 가기” 방지가 가능합니다.
예시: 로그인 후 replace 이동
const navigate = useNavigate();
function afterLogin() {
navigate("/dashboard", { replace: true });
}
→ 사용자가 로그인 후 뒤로 가기를 눌러도 로그인 페이지로 돌아가지 않게 만듭니다.
🪄 Lazy Loading으로 라우트 최적화
페이지 수가 많아지면 번들 파일이 커져서 로딩이 느려질 수 있어요.
이때 Lazy Loading으로 각 페이지를 나눠서 로드하면 성능이 개선됩니다.
React.lazy 사용법
import { lazy, Suspense } from "react";
const Home = lazy(() => import("./pages/Home"));
const About = lazy(() => import("./pages/About"));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>로딩 중...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
→ 컴포넌트가 필요한 시점에만 네트워크로 불러와서 성능 최적화!
🎯 Suspense로 로딩 상태 관리하기
Lazy Loading과 함께 Suspense를 사용하면 네트워크 지연 시간 동안 사용자에게 로딩 화면을 보여줄 수 있어요.
커스텀 로딩 컴포넌트
function Loading() {
return <div>잠시만 기다려주세요...</div>;
}
Suspense 적용
<Suspense fallback={<Loading />}>
<Routes>...</Routes>
</Suspense>
→ UX가 부드러워지고, 페이지 전환이 자연스러워집니다!
🗺️ 다중 레이아웃(Multiple Layouts) 처리하기
사이트에 따라 홈 레이아웃, 관리자 레이아웃 등 다양한 레이아웃이 필요한 경우가 많아요.
이럴 때 중첩 라우트 + Outlet을 조합하면 깔끔하게 구성할 수 있습니다.
예시 구조
function MainLayout() {
return (
<div>
<Header />
<Outlet />
<Footer />
</div>
);
}
function AdminLayout() {
return (
<div>
<AdminSidebar />
<Outlet />
</div>
);
}
라우트 설정
<Route path="/" element={<MainLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
</Route>
<Route path="/admin" element={<AdminLayout />}>
<Route path="dashboard" element={<Dashboard />} />
</Route>
→ 레이아웃별 구조가 명확하고 관리가 쉬워집니다.
🔀 리다이렉트 전략 실전편
사용자가 특정 조건을 만족하지 않으면 자동으로 다른 페이지로 보내야 할 때도 있습니다.
Navigate 사용
import { Navigate } from "react-router-dom";
function MyPage() {
const isLogin = false; // 예시
if (!isLogin) {
return <Navigate to="/login" replace />;
}
return <div>마이페이지 콘텐츠</div>;
}
- replace를 쓰면 브라우저 히스토리에 기록되지 않습니다.
🌐 URL 관리 전략 정리
- 대문자 대신 소문자 사용
- 단수형/복수형 규칙 통일 (
/user
vs/users
) - 동사 대신 명사 사용 (
/create
대신/new
) - SEO를 고려해 간결한 URL 사용
→ URL 자체가 설계 철학을 드러냅니다!
🚥 React Router v6 주요 변화 정리
React Router는 v6에서 많은 변화가 있었어요.
주요 변경 사항
- Switch → Routes로 변경
- Route element 속성 사용 (children이 아님)
- useRoutes 훅 추가로 배열 기반 라우팅 가능
- 중첩 라우트 공식 지원 강화
예시: useRoutes 사용
import { useRoutes } from "react-router-dom";
function App() {
const routing = useRoutes([
{ path: "/", element: <Home /> },
{ path: "/about", element: <About /> }
]);
return routing;
}
→ 컴포넌트 안에서 간결하게 라우트 구성 가능!
📚 마무리하며
React 프로젝트를 만드는 과정에서 **라우팅 시스템을 잘 설계**하는 것은 매우 중요합니다.
단순히 페이지를 이동시키는 것을 넘어서,
- URL 체계 설계
- Protected Route로 접근 제어
- 중첩/동적 라우팅
- Lazy Loading & Suspense 최적화
까지 고려하면, 훨씬 탄탄하고 유지보수하기 쉬운 웹 애플리케이션을 만들 수 있어요.
이제 여러분도 직접 React Router를 활용해서 SPA를 제대로 구축할 수 있을 거예요! 다음 글에서는 React Router + 인증 상태 + 권한에 따라 메뉴 동적 변경 고급편으로 이어갈게요. 🚀
#ReactRouter #SPA개발 #라우팅구현 #중첩라우트 #ProtectedRoute #LazyLoading #ReactSuspense #리액트실전가이드 #퍼블리셔노미