React Router 사용법
이제 SPA에서 가장 중요한 기능 중 하나인 클라이언트 사이드 라우팅을 구현하기 위한 필수 라이브러리인 React Router의 사용법을 배워보겠습니다.
React Router는 리액트 컴포넌트를 URL 경로와 연결하여, 브라우저의 URL이 변경될 때 해당 경로에 맞는 컴포넌트를 렌더링하도록 돕는 라이브러리입니다. 페이지 전체를 새로고침하지 않고도 마치 여러 페이지를 이동하는 듯한 사용자 경험을 제공할 수 있습니다.
React Router 설치
React Router를 사용하려면 먼저 프로젝트에 설치해야 합니다. 터미널에서 다음 명령어를 실행하세요.
npm install react-router-dom
# 또는
yarn add react-router-dom
react-router-dom
은 웹 애플리케이션용 React Router를 포함하고 있습니다. (React Native용은 react-router-native
)
React Router 주요 컴포넌트
React Router를 사용하기 위해 가장 기본적으로 알아야 할 컴포넌트들은 다음과 같습니다.
BrowserRouter
(또는HashRouter
): 라우팅을 적용할 컴포넌트들을 감싸는 최상위 라우터 컴포넌트입니다.BrowserRouter
: HTML5 History API를 사용하여 깔끔한 URL(example.com/about
)을 만듭니다. 서버 설정이 필요할 수 있습니다. (가장 일반적으로 사용)HashRouter
: URL에#
기호(example.com/#/about
)를 사용하여 라우팅을 처리합니다. 서버 설정이 필요 없습니다. (정적 파일 서버 환경에 유용)
Routes
: 여러Route
들을 그룹화하고, 현재 URL과 일치하는 첫 번째Route
를 렌더링합니다. React Router v6부터Switch
대신 사용됩니다.Route
: 특정 URL 경로에 어떤 컴포넌트를 렌더링할지 정의합니다.path
prop: 매칭될 URL 경로element
prop: 렌더링할 리액트 컴포넌트
Link
(또는NavLink
): 페이지 이동을 위한 링크를 생성합니다. HTML의<a>
태그와 유사하지만, 페이지 전체를 새로고침 하지 않고 클라이언트 사이드 라우팅을 수행합니다.to
prop: 이동할 URL 경로NavLink
: 현재 활성화된 경로에 따라active
클래스나 스타일을 적용할 수 있어 내비게이션 바 등에 유용합니다.
useNavigate
Hook: 컴포넌트 내에서 JavaScript 코드로 페이지를 이동해야 할 때 사용하는 훅입니다. (예: 폼 제출 후 리다이렉트)useParams
Hook: URL 경로에 포함된 동적인 파라미터 값을 가져올 때 사용하는 훅입니다.
기본 라우팅 구현 예제
간단한 내비게이션 바와 세 개의 페이지(Home, About, Contact)를 가진 SPA를 만들어 봅시다.
페이지 컴포넌트 생성
src/pages
폴더를 생성하고 Home.js
, About.js
, Contact.js
파일을 만듭니다.
// src/pages/Home.js
import React from 'react';
function Home() {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2 style={{ color: '#2ecc71' }}>환영합니다!</h2>
<p style={{ fontSize: '1.1em', color: '#555' }}>
이곳은 홈페이지입니다. 다양한 기능을 탐색해 보세요.
</p>
<img src="https://via.placeholder.com/300/2ecc71/FFFFFF?text=Home" alt="Home" style={{ marginTop: '20px', borderRadius: '8px' }} />
</div>
);
}
export default Home;
// src/pages/About.js
import React from 'react';
function About() {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2 style={{ color: '#3498db' }}>회사 소개</h2>
<p style={{ fontSize: '1.1em', color: '#555' }}>
저희 회사에 대해 더 자세히 알아보세요.
</p>
<img src="https://via.placeholder.com/300/3498db/FFFFFF?text=About" alt="About" style={{ marginTop: '20px', borderRadius: '8px' }} />
</div>
);
}
export default About;
// src/pages/Contact.js
import React from 'react';
import { useNavigate } from 'react-router-dom'; // useNavigate 훅 임포트
function Contact() {
const navigate = useNavigate(); // useNavigate 훅 사용
const goToHome = () => {
navigate('/'); // '/' 경로로 이동
};
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2 style={{ color: '#e74c3c' }}>문의하기</h2>
<p style={{ fontSize: '1.1em', color: '#555' }}>
궁금한 점이 있다면 언제든지 문의해 주세요.
</p>
<img src="https://via.placeholder.com/300/e74c3c/FFFFFF?text=Contact" alt="Contact" style={{ marginTop: '20px', borderRadius: '8px' }} />
<button
onClick={goToHome}
style={{
marginTop: '30px',
padding: '10px 20px',
backgroundColor: '#e74c3c',
color: 'white',
border: 'none',
borderRadius: '5px',
cursor: 'pointer',
fontSize: '1em'
}}
>
홈으로 돌아가기
</button>
</div>
);
}
export default Contact;
내비게이션 바 컴포넌트 생성
src/components/Navbar.js
파일을 만들고 NavLink
를 사용하여 링크를 만듭니다.
// src/components/Navbar.js
import React from 'react';
import { NavLink } from 'react-router-dom'; // NavLink 임포트
function Navbar() {
const navLinkStyle = ({ isActive }) => {
return {
fontWeight: isActive ? 'bold' : 'normal',
color: isActive ? '#007bff' : '#333',
textDecoration: 'none',
padding: '10px 15px',
margin: '0 10px',
borderRadius: '5px',
transition: 'all 0.3s ease',
backgroundColor: isActive ? '#e7f5ff' : 'transparent',
};
};
return (
<nav style={{
backgroundColor: '#f8f9fa',
padding: '15px 0',
boxShadow: '0 2px 5px rgba(0,0,0,0.1)',
display: 'flex',
justifyContent: 'center',
gap: '20px'
}}>
<NavLink to="/" style={navLinkStyle}>Home</NavLink>
<NavLink to="/about" style={navLinkStyle}>About</NavLink>
<NavLink to="/contact" style={navLinkStyle}>Contact</NavLink>
<NavLink to="/product/123" style={navLinkStyle}>Product (예시)</NavLink> {/* 동적 라우팅을 위한 예시 */}
</nav>
);
}
export default Navbar;
navLinkStyle
함수는isActive
prop을 받아 현재 경로가 활성화되었는지 여부에 따라 동적으로 스타일을 적용합니다.
App.js
에 라우터 설정
src/App.js
파일에서 BrowserRouter
, Routes
, Route
컴포넌트를 사용하여 라우팅을 설정합니다.
// src/App.js
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom'; // 필요한 컴포넌트 임포트
import Navbar from './components/Navbar'; // Navbar 컴포넌트
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';
import ProductDetail from './pages/ProductDetail'; // 다음 예제를 위한 컴포넌트
function App() {
return (
// 최상위에 BrowserRouter로 감싸줍니다.
<BrowserRouter>
<div className="App">
<Navbar /> {/* 내비게이션 바는 모든 페이지에서 보입니다. */}
{/* Routes 컴포넌트 안에 모든 Route들을 정의합니다. */}
<Routes>
{/* path="/" 경로에 Home 컴포넌트 렌더링 */}
<Route path="/" element={<Home />} />
{/* path="/about" 경로에 About 컴포넌트 렌더링 */}
<Route path="/about" element={<About />} />
{/* path="/contact" 경로에 Contact 컴포넌트 렌더링 */}
<Route path="/contact" element={<Contact />} />
{/* 동적 파라미터를 갖는 경로: :id 부분은 동적으로 변할 수 있습니다. */}
<Route path="/product/:id" element={<ProductDetail />} />
{/* 일치하는 경로가 없을 때 렌더링될 컴포넌트 (404 Not Found) */}
<Route path="*" element={
<div style={{ textAlign: 'center', padding: '50px', color: '#888' }}>
<h2>404 Not Found</h2>
<p>페이지를 찾을 수 없습니다.</p>
</div>
} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
실행 및 확인
npm start
(또는 yarn start
) 명령어를 실행하여 애플리케이션을 시작하고 브라우저에서 http://localhost:3000
에 접속합니다.
- 내비게이션 링크를 클릭하여 페이지가 새로고침되지 않고 내용만 바뀌는 것을 확인합니다.
- 브라우저의 뒤로 가기/앞으로 가기 버튼이 정상적으로 작동하는지 확인합니다.
- URL을 직접
http://localhost:3000/about
등으로 변경해도 해당 페이지가 렌더링되는지 확인합니다. Contact
페이지의 '홈으로 돌아가기' 버튼을 클릭했을 때useNavigate
훅을 통해 페이지가 이동하는 것을 확인합니다.
동적 라우팅과 useParams
많은 웹 애플리케이션은 특정 아이템의 상세 페이지(product/1
, users/profile/john-doe
)와 같이 URL 경로에 동적인 값을 포함해야 합니다. React Router는 이를 경로 파라미터(Path Parameters) 를 통해 지원합니다.
ProductDetail.js
생성
src/pages/ProductDetail.js
파일을 만들고 useParams
훅을 사용하여 URL 파라미터 값을 가져옵니다.
// src/pages/ProductDetail.js
import React from 'react';
import { useParams } from 'react-router-dom'; // useParams 훅 임포트
function ProductDetail() {
const { id } = useParams(); // URL 파라미터에서 'id' 값 추출
// 실제 앱에서는 이 id를 사용하여 서버에서 제품 데이터를 가져올 것입니다.
const productData = {
'123': { name: 'React 신발', price: 99000, description: 'React 개발자를 위한 특별한 신발입니다.' },
'456': { name: '리액트 후드티', price: 45000, description: '깔끔한 리액트 로고가 새겨진 후드티입니다.' }
};
const product = productData[id]; // 가상 데이터에서 id에 해당하는 제품 찾기
if (!product) {
return (
<div style={{ padding: '20px', textAlign: 'center', color: '#888' }}>
<h2>제품을 찾을 수 없습니다.</h2>
<p>ID: {id}</p>
</div>
);
}
return (
<div style={{ padding: '20px', textAlign: 'center', border: '1px solid #ddd', borderRadius: '8px', margin: '20px', backgroundColor: '#f9f9f9' }}>
<h2 style={{ color: '#007bff' }}>{product.name} 상세 페이지</h2>
<img src={`https://via.placeholder.com/200/007bff/FFFFFF?text=Product+${id}`} alt={product.name} style={{ marginTop: '20px', borderRadius: '8px' }} />
<p style={{ fontSize: '1.2em', color: '#333', fontWeight: 'bold' }}>
가격: {product.price.toLocaleString()}원
</p>
<p style={{ fontSize: '1.1em', color: '#555' }}>
{product.description}
</p>
<p style={{ fontSize: '0.9em', color: '#777' }}>
현재 보고 있는 제품 ID: <span style={{ fontWeight: 'bold', color: '#007bff' }}>{id}</span>
</p>
</div>
);
}
export default ProductDetail;
useParams()
훅은 객체를 반환하며, 이 객체의 속성 이름은Route
의path
에 정의된 콜론(:
) 뒤의 이름과 일치합니다. (예:path="/product/:id"
->{ id: "값" }
)
실행 및 확인
App.js
에ProductDetail
컴포넌트와Route
가 이미 추가되어 있는지 확인하세요.- 브라우저의 URL에 직접
http://localhost:3000/product/123
또는http://localhost:3000/product/456
을 입력하여 제품 상세 페이지가 렌더링되고,id
값이 올바르게 표시되는지 확인합니다. - Navbar의 "Product (예시)" 링크를 클릭해도 동일한 결과를 볼 수 있습니다.
중첩 라우팅 (Nested Routing)
실제 애플리케이션에서는 특정 경로 아래에 또 다른 하위 경로가 있는 경우가 많습니다. (예: /dashboard/settings
, /dashboard/analytics
). React Router는 중첩 라우팅을 쉽게 구현할 수 있도록 합니다.
중첩 라우팅은 다음 장에서 더 자세히 다루겠습니다.
"React Router 사용법"은 여기까지입니다. 이 장에서는 React Router를 설치하고, BrowserRouter
, Routes
, Route
, Link
, NavLink
, useNavigate
, useParams
와 같은 핵심 컴포넌트 및 훅을 사용하여 기본적인 클라이언트 사이드 라우팅과 동적 라우팅을 구현하는 방법을 상세히 배웠습니다.
이제 여러분은 리액트 SPA에서 페이지 이동 기능을 구현하고 URL에 따라 동적으로 콘텐츠를 렌더링할 수 있는 기본적인 역량을 갖추게 되었습니다.