React Router v6의 필수 네비게이션 패턴을 탐색하세요. 선언적 라우팅, 동적 라우트, 프로그래밍 방식 네비게이션, 중첩 라우트, 데이터 로딩 전략을 배워 견고하고 사용자 친화적인 웹 애플리케이션을 구축하는 방법을 알아보세요.
React Router v6: 최신 웹 앱을 위한 네비게이션 패턴 마스터하기
React Router v6는 React 애플리케이션을 위한 강력하고 유연한 라우팅 라이브러리입니다. 전체 페이지 새로고침 없이 네비게이션을 관리하여 끊김 없는 사용자 경험을 제공하는 단일 페이지 애플리케이션(SPA)을 만들 수 있습니다. 이 블로그 포스트에서는 React Router v6를 사용한 필수 네비게이션 패턴을 깊이 파고들어, 견고하고 사용자 친화적인 웹 애플리케이션을 구축하는 데 필요한 지식과 예제를 제공합니다.
React Router v6 핵심 개념 이해하기
특정 패턴에 대해 알아보기 전에 몇 가지 기본 개념을 살펴보겠습니다:
- 선언적 라우팅: React Router는 선언적 접근 방식을 사용하며, 라우트를 React 컴포넌트로 정의합니다. 이는 라우팅 로직을 명확하고 유지보수하기 쉽게 만듭니다.
- 컴포넌트: 핵심 컴포넌트에는
BrowserRouter
,HashRouter
,MemoryRouter
,Routes
,Route
가 포함됩니다. - 훅(Hooks): React Router는 라우팅 정보에 접근하고 네비게이션을 조작하기 위해
useNavigate
,useLocation
,useParams
,useRoutes
와 같은 훅을 제공합니다.
1. <Routes>
와 <Route>
를 이용한 선언적 라우팅
React Router v6의 기반은 선언적 라우팅에 있습니다. <Routes>
와 <Route>
컴포넌트를 사용하여 라우트를 정의합니다. <Routes>
컴포넌트는 라우트들의 컨테이너 역할을 하며, <Route>
컴포넌트는 특정 라우트와 해당 라우트가 현재 URL과 일치할 때 렌더링할 컴포넌트를 정의합니다.
예제: 기본 라우트 설정
다음은 간단한 애플리케이션의 라우트를 설정하는 기본 예제입니다:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
} />
} />
} />
);
}
export default App;
이 예제에서는 세 가지 라우트를 정의합니다:
/
:Home
컴포넌트를 렌더링합니다./about
:About
컴포넌트를 렌더링합니다./contact
:Contact
컴포넌트를 렌더링합니다.
BrowserRouter
컴포넌트는 브라우저 히스토리 기반 라우팅을 활성화합니다. React Router는 현재 URL을 정의된 라우트와 비교하여 해당하는 컴포넌트를 렌더링합니다.
2. URL 파라미터를 사용한 동적 라우트
동적 라우트를 사용하면 URL의 다른 값들을 처리할 수 있는 라우트를 만들 수 있습니다. 이는 제품 ID나 사용자 ID와 같은 고유 식별자를 기반으로 콘텐츠를 표시하는 데 유용합니다. React Router v6는 :
기호를 사용하여 URL 파라미터를 정의합니다.
예제: 제품 상세 정보 표시
전자상거래 애플리케이션이 있고 각 제품의 ID를 기반으로 상세 정보를 표시하고 싶다고 가정해 봅시다. 다음과 같이 동적 라우트를 정의할 수 있습니다:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
function ProductDetails() {
const { productId } = useParams();
// productId를 기반으로 제품 상세 정보 가져오기
// ...
return (
Product Details
Product ID: {productId}
{/* 여기에 제품 상세 정보 표시 */}
);
}
function App() {
return (
} />
);
}
export default App;
이 예제에서는:
/products/:productId
는:productId
가 URL 파라미터인 동적 라우트를 정의합니다.useParams
훅은ProductDetails
컴포넌트 내에서productId
파라미터의 값에 접근하는 데 사용됩니다.- 그런 다음
productId
를 사용하여 데이터 소스에서 해당하는 제품 상세 정보를 가져올 수 있습니다.
국제화 예제: 언어 코드 처리
다국어 웹사이트의 경우, 동적 라우트를 사용하여 언어 코드를 처리할 수 있습니다:
} />
이 라우트는 /en/about
, /fr/about
, /es/about
와 같은 URL과 일치합니다. 그런 다음 lang
파라미터를 사용하여 적절한 언어 리소스를 로드할 수 있습니다.
3. useNavigate
를 사용한 프로그래밍 방식 네비게이션
선언적 라우팅은 정적 링크에 훌륭하지만, 종종 사용자 작업이나 애플리케이션 로직에 따라 프로그래밍 방식으로 네비게이션해야 할 필요가 있습니다. React Router v6는 이를 위해 useNavigate
훅을 제공합니다. useNavigate
는 다른 라우트로 이동할 수 있게 해주는 함수를 반환합니다.
예제: 폼 제출 후 리디렉션
폼을 제출하고 성공적으로 제출된 후 사용자를 성공 페이지로 리디렉션하고 싶다고 가정해 봅시다:
import { useNavigate } from "react-router-dom";
function MyForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// 폼 데이터 제출
// ...
// 성공적으로 제출 후 성공 페이지로 리디렉션
navigate("/success");
};
return (
);
}
export default MyForm;
이 예제에서는:
useNavigate
훅을 사용하여navigate
함수를 가져옵니다.- 폼이 성공적으로 제출된 후,
navigate("/success")
를 호출하여 사용자를/success
라우트로 리디렉션합니다.
네비게이션 중 상태 전달
navigate
의 두 번째 인수를 사용하여 네비게이션과 함께 상태를 전달할 수도 있습니다:
navigate("/confirmation", { state: { orderId: "12345" } });
이를 통해 대상 컴포넌트에 데이터를 전달할 수 있으며, 이 데이터는 useLocation
훅을 사용하여 접근할 수 있습니다.
4. 중첩 라우트 및 레이아웃
중첩 라우트를 사용하면 한 라우트가 다른 라우트 안에 중첩되는 계층적 라우팅 구조를 만들 수 있습니다. 이는 여러 수준의 네비게이션이 있는 복잡한 애플리케이션을 구성하는 데 유용합니다. 이는 특정 UI 요소가 애플리케이션의 한 섹션 전체에 걸쳐 일관되게 표시되는 레이아웃을 만드는 데 도움이 됩니다.
예제: 사용자 프로필 섹션
사용자의 프로필 정보, 설정 및 주문을 표시하기 위한 중첩 라우트가 있는 사용자 프로필 섹션이 있다고 가정해 봅시다:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function Profile() {
return (
사용자 프로필
-
프로필 정보
-
설정
-
주문
} />
} />
} />
);
}
function ProfileInformation() {
return 프로필 정보 컴포넌트
;
}
function Settings() {
return 설정 컴포넌트
;
}
function Orders() {
return 주문 컴포넌트
;
}
function App() {
return (
} />
);
}
export default App;
이 예제에서는:
/profile/*
라우트는/profile
로 시작하는 모든 URL과 일치합니다.Profile
컴포넌트는 네비게이션 메뉴와 중첩 라우트를 처리하기 위한<Routes>
컴포넌트를 렌더링합니다.- 중첩 라우트는
/profile/info
,/profile/settings
,/profile/orders
에 대해 렌더링할 컴포넌트를 정의합니다.
부모 라우트의 *
는 부모 라우트가 모든 하위 경로와 일치해야 함을 의미하며, 이를 통해 중첩 라우트가 Profile
컴포넌트 내에서 올바르게 일치되도록 합니다.
5. "찾을 수 없음" (404) 오류 처리
사용자가 존재하지 않는 라우트로 이동하는 경우를 처리하는 것이 중요합니다. React Router v6는 catch-all 라우트를 사용하여 이를 쉽게 만듭니다.
예제: 404 페이지 구현
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function NotFound() {
return (
404 - 페이지를 찾을 수 없음
찾으시는 페이지가 존재하지 않습니다.
홈으로 돌아가기
);
}
function App() {
return (
} />
} />
} />
);
}
이 예제에서는:
<Route path="*" element={<NotFound />} />
라우트는 다른 정의된 라우트와 일치하지 않는 모든 URL과 일치하는 catch-all 라우트입니다.- 이 라우트는 다른 라우트가 일치하지 않을 경우에만 일치하도록
<Routes>
컴포넌트의 끝에 배치하는 것이 중요합니다.
6. React Router v6의 데이터 로딩 전략
React Router v6는 이전 버전(useRouteMatch
가 있던 React Router v5)과 달리 내장된 데이터 로딩 메커니즘을 포함하지 않습니다. 그러나 다양한 데이터 로딩 전략을 효과적으로 구현할 수 있는 도구를 제공합니다.
옵션 1: 컴포넌트에서 데이터 가져오기
가장 간단한 접근 방식은 라우트를 렌더링하는 컴포넌트 내에서 직접 데이터를 가져오는 것입니다. useEffect
훅을 사용하여 컴포넌트가 마운트되거나 URL 파라미터가 변경될 때 데이터를 가져올 수 있습니다.
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function ProductDetails() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProduct() {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setProduct(data);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchProduct();
}, [productId]);
if (loading) return 로딩 중...
;
if (error) return 오류: {error.message}
;
if (!product) return 제품을 찾을 수 없습니다
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
이 접근 방식은 간단하지만 여러 컴포넌트에서 데이터를 가져와야 하는 경우 코드 중복으로 이어질 수 있습니다. 또한 데이터 가져오기가 컴포넌트가 마운트된 후에만 시작되므로 덜 효율적입니다.
옵션 2: 데이터 가져오기를 위한 커스텀 훅 사용
코드 중복을 줄이기 위해 데이터 가져오기 로직을 캡슐화하는 커스텀 훅을 만들 수 있습니다. 이 훅은 여러 컴포넌트에서 재사용할 수 있습니다.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
그런 다음 컴포넌트에서 이 훅을 사용할 수 있습니다:
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
function ProductDetails() {
const { productId } = useParams();
const { data: product, loading, error } = useFetch(`/api/products/${productId}`);
if (loading) return 로딩 중...
;
if (error) return 오류: {error.message}
;
if (!product) return 제품을 찾을 수 없습니다
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
옵션 3: 데이터 로딩 기능이 있는 라우팅 라이브러리 사용 (TanStack Router, Remix)
TanStack Router 및 Remix와 같은 라이브러리는 라우팅과 원활하게 통합되는 내장 데이터 가져오기 메커니즘을 제공합니다. 이러한 라이브러리는 종종 다음과 같은 기능을 제공합니다:
- 로더(Loaders): 라우트가 렌더링되기 *전에* 실행되는 함수로, 데이터를 가져와 컴포넌트에 전달할 수 있습니다.
- 액션(Actions): 폼 제출 및 데이터 변경을 처리하는 함수입니다.
이러한 라이브러리를 사용하면 특히 복잡한 애플리케이션의 경우 데이터 로딩을 대폭 단순화하고 성능을 향상시킬 수 있습니다.
서버 사이드 렌더링(SSR) 및 정적 사이트 생성(SSG)
향상된 SEO 및 초기 로딩 성능을 위해 Next.js나 Gatsby와 같은 프레임워크와 함께 SSR 또는 SSG를 사용하는 것을 고려해 보세요. 이러한 프레임워크를 사용하면 서버에서 또는 빌드 타임에 데이터를 가져와 사전 렌더링된 HTML을 클라이언트에 제공할 수 있습니다. 이는 클라이언트가 초기 로드 시 데이터를 가져올 필요가 없게 하여 더 빠르고 SEO 친화적인 경험을 제공합니다.
7. 다양한 라우터 유형 작업하기
React Router v6는 다양한 환경과 사용 사례에 맞는 여러 라우터 구현을 제공합니다:
- BrowserRouter: 네비게이션을 위해 HTML5 히스토리 API(
pushState
,replaceState
)를 사용합니다. 브라우저 환경에서 실행되는 웹 애플리케이션에 가장 일반적인 선택입니다. - HashRouter: 네비게이션을 위해 URL의 해시 부분(
#
)을 사용합니다. 이는 구형 브라우저를 지원해야 하거나 HTML5 히스토리 API를 지원하지 않는 서버에 배포된 애플리케이션에 유용합니다. - MemoryRouter: "URL"의 히스토리를 메모리(URL 배열)에 유지합니다. React Native 및 테스트와 같은 환경에서 유용합니다.
애플리케이션의 요구 사항과 환경에 가장 적합한 라우터 유형을 선택하세요.
결론
React Router v6는 React 애플리케이션을 위한 포괄적이고 유연한 라우팅 솔루션을 제공합니다. 이 블로그 포스트에서 논의된 네비게이션 패턴을 이해하고 적용함으로써 견고하고 사용자 친화적이며 유지보수하기 쉬운 웹 애플리케이션을 구축할 수 있습니다. <Routes>
와 <Route>
를 이용한 선언적 라우팅부터 URL 파라미터를 사용한 동적 라우트, useNavigate
를 사용한 프로그래밍 방식 네비게이션, 효과적인 데이터 로딩 전략에 이르기까지, React Router v6는 사용자에게 원활한 네비게이션 경험을 제공할 수 있도록 지원합니다. 더 큰 제어와 성능 최적화를 위해 고급 라우팅 라이브러리와 SSR/SSG 프레임워크를 탐색하는 것을 고려해 보세요. 특정 애플리케이션 요구 사항에 맞게 이러한 패턴을 조정하고 항상 명확하고 직관적인 사용자 경험을 우선시하는 것을 잊지 마세요.