useParams, useSearchParams, useNavigate



1. React Router 훅이란?

React Router에서 제공하는 훅(Hook)은 페이지 간 이동과 URL 관련 정보를 쉽게 처리할 수 있도록 합니다. 그 중에서도 useParams, useSearchParams, useNavigate는 URL 경로의 파라미터, 쿼리 파라미터, 페이지 이동에 있어 제어하는데 필수적인 훅입니다.


2. React Router 훅

1) useParams로 URL 경로 파라미터 추출

useParams는 URL 경로에서 동적 경로 파라미터를 추출하는 훅입니다. 예를 들어, /products/:productId와 같은 경로에서 :productId에 해당하는 값을 가져와 사용할 수 있습니다.

components/ProductList.js

import React from "react";
import ProductItem from "./ProductItem";

export const productInfos = [
  {
    userId: 1,
    id: 1,
    title: "첫 번째 상품",
    body: "첫 번째 상품 설명입니다.",
  },
  {
    userId: 1,
    id: 2,
    title: "두 번째 상품",
    body: "두 번째 상품 설명입니다.",
  },
];

export default function ProductList() {
  return (
    <div>
      {productInfos.map((product) => (
        <ProductItem key={product.id} product={product} />
      ))}
    </div>
  );
}

pages/ProductDetailPage.js

import React from "react";
import { useParams } from "react-router-dom";
import { productInfos } from "../components/ProductList";

export default function ProductDetailPage() {
  const { productId } = useParams(); // URL 경로에서 productId를 추출
  console.log("productId >>> ", productId); // '3' = 'id'
  const targetProduct = productInfos[Number(productId) - 1]; // productId로 배열에서 해당 상품 조회

  return (
    <div>
      <h1>ProductDetailPage</h1>
      <ul>
        <li>상품번호: {targetProduct.id}</li>
        <li>상품명: {targetProduct.title}</li>
        <li>판매자: {targetProduct.userId}</li>
        <li>상세설명: {targetProduct.body}</li>
      </ul>
    </div>
  );
}
  • productInfos는 상품 정보를 담은 배열입니다. 각 상품은 id, title, userId, body의 속성을 가진 객체로 정의되어 있으며, 배열 안에 여러 상품이 있습니다.
  • 배열 인덱스와 파라미터 값 차이: 파라미터로 전달된 productId는 1부터 시작하지만, 배열의 인덱스는 0부터 시작하므로, -1을 적용하여 배열의 요소에 접근할 수 있습니다.


2) useSearchParams로 쿼리 파라미터 관리하기

useSearchParams는 URL의 쿼리 파라미터를 읽고, 이를 동적으로 수정할 수 있는 훅입니다. 쿼리 파라미터는 URL 뒤에 ?key=value 형태로 붙으며, 검색 조건, 필터링 등에 주로 사용됩니다.

/pages/MainPage.js

import React from "react";
import { useSearchParams } from "react-router-dom";

export default function MainPage() {
  const [searchParams, setSearchParams] = useSearchParams(); // 현재 쿼리 파라미터를 가져옴
  const currentMode = searchParams.get("mode") || ""; // 쿼리에서 'mode' 값 추출

  const toggleMode = () => {
    if (currentMode === "Dark") {
      searchParams.delete("mode"); // Dark 모드일 때 쿼리 파라미터 삭제
      setSearchParams(searchParams);
    } else {
      setSearchParams({ mode: "Dark" }); // Dark 모드로 설정
    }
  };

  return (
    <div className={`Main ${searchParams.get("mode") || ""}`}>
      <h1>MainPage</h1>
      <button onClick={toggleMode}>
        {currentMode === "Dark" ? "Default Mode" : "Dark Mode"}
      </button>
    </div>
  );
}

(1) 쿼리 파라미터와 || 연산자

  • 쿼리 파라미터는 URL의 일부로, 페이지 상태나 필터 조건을 유지하기 위해 사용됩니다. 예를 들어, ?mode=Dark라는 쿼리 파라미터는 페이지가 다크 모드인지 여부를 나타낼 수 있습니다.
  • setSearchParams를 이용해 쿼리 파라미터를 동적으로 변경하거나 삭제할 수 있습니다. 위 코드에서는 버튼을 클릭하면 쿼리 파라미터가 mode=Dark로 설정되거나, 삭제되어 기본 모드로 전환됩니다.

  • || 연산자 사용:
    • searchParams.get('mode')null일 때(falsy), || 연산자가 작동하여 빈 문자열 ''을 반환합니다. 이를 통해 null이나 undefined 대신 기본값을 지정할 수 있습니다.
    • 예를 들어, 쿼리 파라미터가 없을 때, currentMode는 빈 문자열이 됩니다.
      const currentMode = searchParams.get("mode") || ""; // 없으면 '' 반환
      

(2) 다크 모드 설정 방식

이 부분에서는 CSS 클래스를 동적으로 적용하여 다크 모드와 기본 모드를 변경하는 방식이 두 가지로 나뉩니다.

join을 사용하는 방법
  • 배열에 클래스 이름들을 넣고, join 메서드를 사용하여 공백을 기준으로 합칩니다. 이는 클래스 이름을 다루기 쉽게 만들어줍니다.
<div className={['Main', searchParams.get('mode')].join(' ')}>
<!-- [Main, Dark].join(' ') => Main Dark -->
백틱( )을 사용하는 방법
  • 템플릿 리터럴을 이용하여 백틱으로 문자열을 생성하고, 조건에 따라 클래스 이름을 삽입합니다.
<div className={`Main ${searchParams.get('mode') || ''}`}>

(3) CSS로 다크 모드 구현

.Main {
  background-color: #ddd;
}

.Main.Dark {
  background-color: #333;
  color: #fff;
}
  • Main 클래스는 기본 모드를 나타내고, Main.Dark는 다크 모드에서 사용될 CSS입니다.
  • 다크 모드일 때: 쿼리 파라미터가 mode=Dark이면, Main Dark라는 클래스가 적용됩니다.
  • 기본 모드일 때: mode 쿼리 파라미터가 없으면 기본적인 Main 클래스만 적용됩니다.


3) useNavigate로 페이지 이동 제어

/pages/ProductDetailPage.js

import React from "react";
import { useNavigate, useParams } from "react-router-dom";
import { productInfos } from "../components/ProductList";

export default function ProductDetailPage() {
  const { productId } = useParams();
  const navigate = useNavigate(); // 페이지 이동을 위한 훅

  const targetProduct = productInfos[Number(productId) - 1];

  return (
    <div>
      <h1>ProductDetailPage</h1>
      <button onClick={() => navigate(-1)}>뒤로가기</button> {/* -1: 이전 페이지로 이동 */}
      <button onClick={() => navigate("/")}>홈으로 이동하기</button>{" "}
      {/* 홈으로 이동 */}
      <ul>
        <li>상품번호: {targetProduct.id}</li>
        <li>상품명: {targetProduct.title}</li>
        <li>판매자: {targetProduct.userId}</li>
        <li>상세설명: {targetProduct.body}</li>
      </ul>
    </div>
  );
}
  • navigate(-n): -1을 사용하면 이전 페이지로 이동합니다. 이는 브라우저의 뒤로가기 버튼과 동일한 기능을 합니다.
  • navigate(n): 1을 사용하면 다음 페이지로 이동합니다. 이는 브라우저의 앞으로 가기 버튼과 동일한 기능을 합니다.
  • navigate('/'): 홈 페이지로 직접 이동할 수 있습니다.