[ React 블로그 개발 ] 6. Navigation(라우팅) 연동하는 방법
2025-09-09
route (navigation) 연동
1. 왜 Navigation이 필요할까?
React는 기본적으로 SPA(Single Page Application)이기 때문에, 페이지가 전환되는 것처럼 보여도 실제로는 하나의 HTML 파일 안에서 컴포넌트만 바뀝니다.
하지만 블로그, 쇼핑몰, 대시보드 등 실제 서비스에서는 URL에 따라 다른 화면을 보여주고, 사용자가 '뒤로가기', '앞으로가기' 등 네비게이션을 자연스럽게 할 수 있어야 합니다.
이를 위해 라우터 라이브러리를 사용합니다.
2. 대표적인 라이브러리
React에서 가장 많이 쓰는 라우터 라이브러리는 React Router입니다.
- 공식 라이브러리, 커뮤니티도 큼
- 다양한 기능: 동적 라우팅, 파라미터, 중첩 라우트, 네비게이션 등
3. 설치 방법
터미널에서 아래 명령어로 설치하세요.
npm install react-router-dom
# 또는
yarn add react-router-dom
4. 기본 사용법
4.1. 라우터 세팅 (최상위 컴포넌트에 BrowserRouter)
-
import { BrowserRouter } from "react-router-dom" function App() { return ( <BrowserRouter> <YourRoutes /> </BrowserRouter> ) }
4.2. Route 정의 및 페이지 컴포넌트 연결
-
import { Routes, Route } from 'react-router-dom' import Home from './Home' import About from './About' function YourRoutes() { return ( <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> {/* 추가적으로 원하는 라우트 */} </Routes> ) }
4.3. 네비게이션(페이지 이동) 방법
1) Link 컴포넌트 사용
-
import { Link } from 'react-router-dom'; <Link to="/about">About 페이지로 이동</Link>
2) useNavigate 훅 사용 (코드로 이동)
-
import { useNavigate } from 'react-router-dom'; function MyComponent() { const navigate = useNavigate(); const goToAbout = () => { navigate('/about'); }; return <button onClick={goToAbout}>About으로 이동</button>; }
5. 라우트 파라미터와 쿼리스트링
5.1. 동적 파라미터
-
<Route path="/post/:postId" element={<PostPage />} /> /post/123방문 시,postId에123이 들어감-
import { useParams } from 'react-router-dom'; function PostPage() { const { postId } = useParams(); // postId로 API 호출 등 }
5.2. 쿼리스트링 읽기
-
import { useLocation } from 'react-router-dom'; function SearchPage() { const location = useLocation(); const query = new URLSearchParams(location.search); const keyword = query.get('keyword'); }
6. 코드 적용하기
-
main.tsx
- react-router-dom 을 저희 페이지에 적용시켜 줍니다.
-
import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import { AppTopComponent, MainComponent, SidebarLeft, SidebarRight, TopComponent, } from "./components/index.ts"; import "./index.css"; import { Mobile, PC } from "./utils/MobileCheck.tsx"; export const AppEntry = () => { return ( <BrowserRouter> <div style={{ width: "100%", }} > <PC> <TopComponent /> </PC> <Mobile> <AppTopComponent /> </Mobile> <div style={{ width: "100%", display: "flex", flexDirection: "row" }}> <PC> <SidebarLeft /> </PC> <MainComponent /> <PC> <SidebarRight /> </PC> </div> </div> </BrowserRouter> ); }; createRoot(document.getElementById("root")!).render( <StrictMode> <AppEntry /> </StrictMode> );
-
src/screens/PostListScreen.tsx 를 추가시켜줍니다.
- 저희 글의 리스트를 메뉴별로 따로 가져오게 하려고 합니다.
-
import { useState } from "react"; import { useNavigate } from "react-router-dom"; export default function SidebarLeft() { const navigation = useNavigate(); const [activeMenu, setActiveMenu] = useState<number | null>(null); // 드롭다운 상태 관리 const menus = [ { no: 1, title: "React Menu 1", subMenus: [ { no: 1, title: "React SubMenu 1-1", }, { no: 3, title: "React SubMenu 1-2", }, ], }, { no: 2, title: "React Menu 2", subMenus: [ { no: 2, title: "React SubMenu 2-1", }, { no: 4, title: "React SubMenu 2-2", }, ], }, ]; const toggleDropdown = (menuNo: number) => { setActiveMenu((prev) => (prev === menuNo ? null : menuNo)); // 클릭 시 드롭다운 토글 }; return ( <div style={{ alignItems: "center", justifyContent: "center", display: "flex", flexDirection: "column", width: "20%", }} > <div style={{ margin: 10, fontWeight: 900, fontSize: 17 }}>MENU</div> {menus?.map((menu) => ( <div key={menu.no} style={{ width: "100%" }}> <div onClick={() => toggleDropdown(menu.no)} style={{ padding: "10px", cursor: "pointer", textAlign: "center", backgroundColor: activeMenu === menu.no ? "#f0f0f0" : "transparent", // 드롭다운 활성화 시 배경색 변경 }} > {menu.title} </div> {activeMenu === menu.no && menu.subMenus?.map((subMenu) => ( <div key={subMenu.no} onClick={() => { navigation(`/post/list/${subMenu.no}`); setActiveMenu(null); // 서브 메뉴 클릭 시 드롭다운 닫기 }} style={{ padding: "10px 20px", cursor: "pointer", textAlign: "center", backgroundColor: "#f9f9f9", }} > {subMenu.title} </div> ))} </div> ))} </div> ); }
-
src/navigaton/RootNavigation.tsx 를 추가시켜줍니다.
- 적용한 react-router-dom을 이용하여 Route를 쌓아줍니다
- path는 저희가 설정한 뒤, 해당 path를 이용하면 저희가 원하는 페이지(element)로 이동할 수 있어요
-
import { Route, Routes } from "react-router-dom"; import { MainScreen } from "../screens"; import PostListScreen from "../screens/PostListScreen"; export default function RootNavigation() { return ( <> <Routes> <Route path="/" element={<MainScreen />} /> <Route path="/post/list/:subMenuNo" element={<PostListScreen />} /> </Routes> </> ); }
-
src/navigation/index.ts 도 추가시켜줍니다.
- 이전에 포스팅했던 배럴 파일 패턴으로 적용해줍니다.
-
export { default as RootNavigation } from "./RootNavigation";
-
MainComponent.tsx
- 위쪽에서 만든 RootNavigation을 적용해줍니다.
- MainComponent 내부에 RootNavigation을 넣은 이유는
- Top, Left, Right에 위치한 Component들은 고정하고, 중앙 영역에 있는 내용만 바뀌게 하기 위함입니다.
-
import { RootNavigation } from "../navigator"; export default function MainComponent() { return ( <div className="main-component" style={{ width: "100%" }}> <RootNavigation /> </div> ); }
-
SidebarLeft.tsx
- 이제 router 연동을 끝냈으니 메뉴 버튼을 클릭하면 이동시키는 작업을 해보겠습니다.
-
import { useState } from "react"; import { useNavigate } from "react-router-dom"; export default function SidebarLeft() { const navigation = useNavigate(); const [activeMenu, setActiveMenu] = useState<number | null>(null); // 드롭다운 상태 관리 const menus = [ { no: 1, title: "React Menu 1", subMenus: [ { no: 1, title: "React SubMenu 1-1", }, { no: 3, title: "React SubMenu 1-2", }, ], }, { no: 2, title: "React Menu 2", subMenus: [ { no: 2, title: "React SubMenu 2-1", }, { no: 4, title: "React SubMenu 2-2", }, ], }, ]; const toggleDropdown = (menuNo: number) => { setActiveMenu((prev) => (prev === menuNo ? null : menuNo)); // 클릭 시 드롭다운 토글 }; return ( <div style={{ alignItems: "center", justifyContent: "center", display: "flex", flexDirection: "column", width: "20%", }} > <div style={{ margin: 10, fontWeight: 900, fontSize: 17 }}>MENU</div> {menus?.map((menu) => ( <div key={menu.no} style={{ width: "100%" }}> <div onClick={() => toggleDropdown(menu.no)} style={{ padding: "10px", cursor: "pointer", textAlign: "center", backgroundColor: activeMenu === menu.no ? "#f0f0f0" : "transparent", // 드롭다운 활성화 시 배경색 변경 }} > {menu.title} </div> {activeMenu === menu.no && menu.subMenus?.map((subMenu) => ( <div key={subMenu.no} onClick={() => { navigation(`/post/list/${subMenu.no}`); setActiveMenu(null); // 서브 메뉴 클릭 시 드롭다운 닫기 }} style={{ padding: "10px 20px", cursor: "pointer", textAlign: "center", backgroundColor: "#f9f9f9", }} > {subMenu.title} </div> ))} </div> ))} </div> ); }
-
적용하고 메뉴를 눌러보세요
-
바뀌시는게 보이나요~?
7. 마무리 및 참고
- 공식 문서: React Router 공식 문서
- 네비게이션, 동적 페이지, 쿼리스트링 등 다양한 기능이 있으니 공식 문서도 함께 참고하세요!
- 포스팅중인 React Sample Source Git 주소