한국어

React Router v6의 필수 네비게이션 패턴을 탐색하세요. 선언적 라우팅, 동적 라우트, 프로그래밍 방식 네비게이션, 중첩 라우트, 데이터 로딩 전략을 배워 견고하고 사용자 친화적인 웹 애플리케이션을 구축하는 방법을 알아보세요.

React Router v6: 최신 웹 앱을 위한 네비게이션 패턴 마스터하기

React Router v6는 React 애플리케이션을 위한 강력하고 유연한 라우팅 라이브러리입니다. 전체 페이지 새로고침 없이 네비게이션을 관리하여 끊김 없는 사용자 경험을 제공하는 단일 페이지 애플리케이션(SPA)을 만들 수 있습니다. 이 블로그 포스트에서는 React Router v6를 사용한 필수 네비게이션 패턴을 깊이 파고들어, 견고하고 사용자 친화적인 웹 애플리케이션을 구축하는 데 필요한 지식과 예제를 제공합니다.

React Router v6 핵심 개념 이해하기

특정 패턴에 대해 알아보기 전에 몇 가지 기본 개념을 살펴보겠습니다:

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;

이 예제에서는 세 가지 라우트를 정의합니다:

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;

이 예제에서는:

국제화 예제: 언어 코드 처리

다국어 웹사이트의 경우, 동적 라우트를 사용하여 언어 코드를 처리할 수 있습니다:


} />

이 라우트는 /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;

이 예제에서는:

네비게이션 중 상태 전달

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 컴포넌트 내에서 올바르게 일치되도록 합니다.

5. "찾을 수 없음" (404) 오류 처리

사용자가 존재하지 않는 라우트로 이동하는 경우를 처리하는 것이 중요합니다. React Router v6는 catch-all 라우트를 사용하여 이를 쉽게 만듭니다.

예제: 404 페이지 구현


import { BrowserRouter, Routes, Route, Link } from "react-router-dom";

function NotFound() {
  return (
    

404 - 페이지를 찾을 수 없음

찾으시는 페이지가 존재하지 않습니다.

홈으로 돌아가기
); } function App() { return ( } /> } /> } /> ); }

이 예제에서는:

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 RouterRemix와 같은 라이브러리는 라우팅과 원활하게 통합되는 내장 데이터 가져오기 메커니즘을 제공합니다. 이러한 라이브러리는 종종 다음과 같은 기능을 제공합니다:

이러한 라이브러리를 사용하면 특히 복잡한 애플리케이션의 경우 데이터 로딩을 대폭 단순화하고 성능을 향상시킬 수 있습니다.

서버 사이드 렌더링(SSR) 및 정적 사이트 생성(SSG)

향상된 SEO 및 초기 로딩 성능을 위해 Next.js나 Gatsby와 같은 프레임워크와 함께 SSR 또는 SSG를 사용하는 것을 고려해 보세요. 이러한 프레임워크를 사용하면 서버에서 또는 빌드 타임에 데이터를 가져와 사전 렌더링된 HTML을 클라이언트에 제공할 수 있습니다. 이는 클라이언트가 초기 로드 시 데이터를 가져올 필요가 없게 하여 더 빠르고 SEO 친화적인 경험을 제공합니다.

7. 다양한 라우터 유형 작업하기

React Router v6는 다양한 환경과 사용 사례에 맞는 여러 라우터 구현을 제공합니다:

애플리케이션의 요구 사항과 환경에 가장 적합한 라우터 유형을 선택하세요.

결론

React Router v6는 React 애플리케이션을 위한 포괄적이고 유연한 라우팅 솔루션을 제공합니다. 이 블로그 포스트에서 논의된 네비게이션 패턴을 이해하고 적용함으로써 견고하고 사용자 친화적이며 유지보수하기 쉬운 웹 애플리케이션을 구축할 수 있습니다. <Routes><Route>를 이용한 선언적 라우팅부터 URL 파라미터를 사용한 동적 라우트, useNavigate를 사용한 프로그래밍 방식 네비게이션, 효과적인 데이터 로딩 전략에 이르기까지, React Router v6는 사용자에게 원활한 네비게이션 경험을 제공할 수 있도록 지원합니다. 더 큰 제어와 성능 최적화를 위해 고급 라우팅 라이브러리와 SSR/SSG 프레임워크를 탐색하는 것을 고려해 보세요. 특정 애플리케이션 요구 사항에 맞게 이러한 패턴을 조정하고 항상 명확하고 직관적인 사용자 경험을 우선시하는 것을 잊지 마세요.