2026. 1. 3. 21:40ㆍSTUDY
리액트는 단일 페이지 애플리케이션(SPA;Single Page Application)을 구축하기 위한 라이브러리.
SPA는 전체를 새로고침하지 않고 필요한 부분만 바꾸는 방식
React Router DOM은 브라우저의 주소(URL)와 UI를 동기화 해주는 표준 라이브러리
사용자가 특정 주소로 들어오거나 버튼을 눌러 경로를 바꿀때, 서버에 새로운 HTML을 요청하지 않고 자바스크립트가 동적으로 화면을 그림
→ URL에 따라 어떤 컴포넌트를 보여줄지 결정하는 것
✓ SPA (Single Page Application)
단 하나의 HTML 페이지에서 모든 콘텐츠를 로드하고, 사용자의 상호작용에 따라 페이지 전체를 새로고침하지 않고 동적으로 콘텐츠만 변경하여 부드럽고 빠른 사용자 경험을 제공하는 웹 애플리케이션 방식
마치 네이티브 앱처럼 동작하여 모바일 환경에서도 최적화된 성능을 보여주는 것이 특징이며,
React, Vue.js, Angular 같은 기술로 개발
왜 사용하는가
- 페이지 전환시 새로고침없이 앱처럼 부드러운 느낌을 준다.
- 자바스크립트로 화면을 바꾸지만, 브라우저의 히스토리 API와 연동되어 일반 사이트처럼 뒤로가기 버튼 작동
- 선언적라우팅 '이 경로(/)일땐 이 컴포넌트(Home)을 보여줘' 라고 명확하게 선언할수있어 파악이 쉽다.
- 중첩 라우팅, 특정 페이지 안에 특정 부분만 바뀌는 상세 탭 등의 구조 잡기 최적화
컴포넌트방식 <BrowserRouter>
<Routes>, <Route> 태그로 작성하여 직관적이고 배우기 쉽지만, 데이터를 미리 불러온느 기능이나 액션 기능을 활용하기 어렵다.
- BrowserRouter: 라우팅을 적용할 최상위 컴포넌트
- Routes & Route: 경로와 컴포넌트를 매핑
- Navigate: 특정 조건에서 페이지를 강제로 이동시킬 때 사용
<BrowserRouter>
<Routes>
<Route path="feed" element={<FeedPage />} />
...
{/* 기본 경로를 피드로 리다이렉트 */}
<Route index element={<Navigate to="/feed" replace />} />
</Routes>
</BrowserRouter>
객체 설정 방식 createBrowserRouter -- 현재 권장 방식
React Router DOM 버전 6.4 이상에서 도입된 'Data APIs' 방식
createBrowserRouter함수에 경로 객체 배열을 전달하고, <RouterProvider />로 실행
- DataFetching 페이지를 렌더링하기 전에 데이터를 미리 가져오는 loader 기능을 사용
- 에러핸들링 errorElement를 통해 특정 경로 에러가 났을때 보여줄 화면을 개별적으로 설정 가능
- 중첩라우팅 children 구조를 통해 계층 파악
const router = createBrowserRouter([
{
path: "/",
element: <App />,
children: [
{
path: "",
element: <Layout />,
children: [
{ path: "feeds", element: <Feed /> },
{ path: "post", element: <Post /> },
{ path: "search", element: <Search /> },
{ path: "mypage", element: <MyPage /> },
],
},
],
},
]);
export default router;
동적라우팅(Dynamic Routing)
1) 컴포넌트방식
Route 태그의 path 속성에 **콜론(:)**을 사용하여 변수명을 지정
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
{/* :postId 부분이 동적으로 변하는 파라미터가 됩니다 */}
<Route path="post/:postId" element={<PostDetail />} />
</Route>
</Routes>
</BrowserRouter>
2) 객체방식
path 문자열에 동일하게 콜론(:)을 사용합니다. 구조가 객체 배열이라는 점만 다름
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{
path: "post/:postId", // 동적 파라미터 정의
element: <PostDetail />,
},
],
},
]);
3) 데이터 가져오기 (useParams)
실제 페이지 컴포넌트에선 useParams 훅을 사용하여 URL에 포함된 값을 가져옫다.
import { useParams } from 'react-router-dom';
type PostParams = {
postId: string;
};
export default function PostDetail () {
const { postId } = useParams<PostParams>();
// const { postId } = useParams() as { postId: string };
return (...);
};
내부에서 페이지를 이동(Navigation)시키는 방법
<Link> 컴포넌트 (선언적 이동)
사용자가 직접 클릭해서 이동해야하는 UI(메뉴, 버튼 형태의 링크)에서 사용
주소창의 URL만 바꾸고 화면의 필요한 부분만 교체함
import { Link } from 'react-router-dom';
const Menu = () => {
return (
<ul>
<li><Link to="/feeds">피드 페이지로 가기</Link></li>
<li><Link to="/mypage">마이페이지로 가기</Link></li>
</ul>
);
};
<Link> 와 <a> 태그의 차이점은 새로고침 유무
<a> 태그는 브라우저가 서버에 해당 페이지 HTML을 요청하기때문에 화면이 깜박이면서 전체 리소스(JS/CSS)를 다시 다운로드
→ 모든 상태가 초기화 된다.
useNavigate (프로그래밍 방식 이동)
사용자 클릭뿐만 아니라 특정 로직이 완료된 후 강제 페이지 이동할때 사용
e.g. 로그인 API 호출
import { useNavigate } from 'react-router-dom';
const LoginForm = () => {
const navigate = useNavigate();
const handleLogin = async () => {
const success = await loginApi();
if (success) {
navigate('/feeds');
} else {
alert("로그인에 실패했습니다.");
}
};
return <button onClick={handleLogin}>로그인하기</button>;
};
✓ 자주 사용하는 브라우저 히스토리 제어 -- useNavigate 훅
뒤로가기, 앞으로가기 등
import { useNavigate } from 'react-router-dom'; export default function PostDetail() { const navigate = useNavigate(); return ( <div> {/* 1. 단순 뒤로 가기 (-1은 한 단계 전을 의미) */} <button onClick={() => navigate(-1)}>뒤로 가기</button> {/* 2. 한 단계 앞으로 가기 */} <button onClick={() => navigate(1)}>앞으로 가기</button> {/* 3. 특정 페이지로 이동하면서 히스토리 삭제 (replace) */} <button onClick={() => navigate('/login', { replace: true })}> 로그아웃 (뒤로가기 방지) </button> </div> ); }
Outlet
중첩라우팅(Nested Routing)을 구현하는데 중요한개념.
부모 라우트가 자식라우트를 가질때, 부모컴포넌트 내에서 자식컴포넌트를 렌더링돌 위치를 표시
(Nextjs 의 App Router에서 layout.tsx의 {children} 역할)
- UI 재상용성: 헤더, 사이드바와 같은 공통 UI를 한번만 작성
- 부분렌더링: 페이지 전체를 새로그리는 것이 아닌 변화가 있는 자식 컴포넌트 영역(outlet) 만 교체
- 구조적 명확성: 계층 구조를 명확하게 하여 코드 유지보수에 좋음
구현예시
GNB(Global Navigation Bar)가 포함된 레이아웃 구조
1) 부모 레이아웃 Layout.tsx (components/Layout.tsx) -- 공통 레이아웃으로 Outlet 포함
import { Link, Outlet } from 'react-router-dom';
const Layout = () => {
return (
<div className="app-container">
<header>
<nav>
<Link to="/feed">피드</Link>
<Link to="/mypage">마이페이지</Link>
</nav>
</header>
<main className="content">
<Outlet />
</main>
<footer>© 2026 My Blog</footer>
</div>
);
};
✓ useOutletContext란?
outlet에서는 content속성을 사용하면 자식 페이지에 부모데이터를 자유롭게 꺼내 사용가능
2) 라우터에서 연결 (App.tsx)
부모 Route 아래에 자식 Route들을 배치
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Layout from './components/Layout';
import Feed from './pages/Feed';
import MyPage from './pages/MyPage';
const router = createBrowserRouter([
{
path: "/",
element: <Layout />, // 부모가 Layout이 됨
children: [
{
path: "feed",
element: <Feed />, // /feed 접속 시 Layout의 Outlet 자리에 위치
},
{
path: "mypage",
element: <MyPage />, // /mypage 접속 시 Layout의 Outlet 자리에 위치
},
],
},
]);
export default function App() {
return <RouterProvider router={router} />;
}
1) <Link> 컴포넌트의 차이
Next.js의 Link는 사용자가 클릭하기도 전에 이미 갈 페이지의 데이터를 준비
| React Router (Link) | Next.js (next/link) | |
| 새로고침 방지 | 지원 | 지원 |
| Prefetching | 없음 | 기본지원(뷰포트에 링크가 보이면 미리 로드) |
| 동작 방식 | JS가 주소만 바꿈 | 서버로부터 최적화된 JSON데이터를 미리 받아둠 |
2) 페이지 이동 훅 (Navigation)
React: useNavigate() → Maps('/feeds')
Next.js: useRouter() → router.push('/feeds')
"use client";
import { useRouter } from 'next/navigation';
export default function PostItem({ id }: { id: string }) {
const router = useRouter();
return (<>
<Link href={`/post/${post.id}`}>{post.title}</Link>
<button onClick={() => router.push(`/post/${id}`)}>
자세히 보기
</button>
</>);
}
3) 레이아웃 시스템 (Outlet vs children)
React의 Outlet이 했던 역할은 Next.js에서는 layout.tsx의 {children}이 담당
4) 동적 라우팅
Next.js App Router에선 폴더 이름을 [id] 와 같이 대괄호에 감싸면 된다.
interface PostPageProps {
params: {
postId: string;
};
}
export default function PostDetailPage({ params }: PostPageProps) {
const { postId } = params;
return (...);
}
| React Router (Link) | Next.js (next/link) | |
| 정의방식 | 코드 <Route path="post/:id" /> |
파일 app/post/[id]/page.tsx |
| 값읽기 | useParams() 훅 사용 | props.params로 직접 수신 (서버) |
| 특이점 | 클라이언트 측에서만 동작 | 서버/클라이언트 모두 지원 및 SEO 최적화 |
| 다중파라미터 | :category/:id | [category]/[id] 폴더 구조 |
✓ Catch-all Segments ([...])
만약 계층이 불분명하고, 아주 긴 주소를 모두 하나의 페이지에서 처리하고싶은경우
폴더명: app/shop/[...slug]/page.tsx
/shop/a, /shop/a/b, /shop/a/b/c를 모두 하나의 페이지가 담당하며, params.slug는 ['a', 'b', 'c'] 형태의 배열
💡 요즘은 Next.js로 개발을 하다 보니 다시 리액트 프로젝트를 할 때 헷갈리는 부분 중 하나가 바로 React Router DOM 설정입니다.
Next.js는 별도의 라이브러리 설치 없이 폴더 구조가 곧 URL 경로가 되는 '파일 시스템 라우팅'을 제공하기 때문입니다.
- React Router DOM은 개발자에게 라우팅에 대한 모든 제어권을 부여한다.
경로 하나하나를 명시적으로 선언하기 때문에 규모가 작은 SPA나 커스텀 제어가 많이 필요한 프로젝트에서 여전히 강력한 도구
- Next.js는 설정보다 관습(Convention over Configuration)을 따릅니다.
복잡한 라우팅 설정을 폴더 구조로 대체하여 생산성을 높이고, Prefetching 같은 성능 최적화를 기본으로 제공하여 사용자 경험을 극대화

'STUDY' 카테고리의 다른 글
| Next.js(App Router) URL의 파라미터(id)를 가져오는 방식 (서버 컴포넌트와 클라이언트 컴포넌트) (0) | 2026.01.12 |
|---|---|
| SEO를 위한 시맨틱 마크업 (0) | 2026.01.10 |
| Zustand와 Next.js, 안전한 데이터 동기화(Hydration) (0) | 2026.01.04 |
| 상태 관리 라이브러리 -- Zustand (0) | 2026.01.02 |
| React Hooks 정리 (0) | 2026.01.01 |