개발 공부/Next.js

쿼리 파라미터(searchParams/useSearchParams) & 경로정보(params/usePathname )

Ryomi 2025. 1. 3. 11:14
728x90
반응형

 

정리

searchParams vs useSearchParams

특징  searchParams  useSearchParams
사용 환경 서버 컴포넌트 클라이언트 컴포넌트
선언 방식 props로 자동 전달 React Hook으로 import
데이터 형태 일반 객체 URLSearchParams 객체
사용 방법 searchParams.category searchParams.get('category')
변경 감지 페이지 새로고침 실시간 (자동 갱신)
주 사용 목적 초기 데이터 로딩, SEO 동적 필터링, 실시간 업데이트

 

params vs usePathname

특징  params  usePathname
사용 환경 서버 컴포넌트 클라이언트 컴포넌트
선언 방식 props로 자동 전달 React Hook으로 import
반환 값 동적 라우트 파라미터 객체 전체 경로 문자열
사용 예시 params.slug pathname (전체 경로)
주요 용도 동적 라우팅 처리 현재 경로 기반 UI 업데이트
데이터 범위 동적 세그먼트만 포함 전체 URL 경로 반환

 

쿼리 파라미터 관리하기

1. searchParams prop 사용

// app/teams/page.tsx
export default function TeamsPage({
  searchParams,
}: {
  searchParams: { filter: string; sort: string }
}) {
  return (
    <div>
      <h1>팀 목록</h1>
      <p>필터: {searchParams.filter}</p>
      <p>정렬: {searchParams.sort}</p>
    </div>
  );
}

 

2. useSearchParams 훅 활용 (클라이언트 컴포넌트)

// components/TeamFilter.tsx
'use client';
import { useSearchParams } from 'next/navigation';

export default function TeamFilter() {
  const searchParams = useSearchParams();
  const filter = searchParams.get('filter');

  return (
    <div>
      <h2>현재 필터</h2>
      <div className="filter-status">
        {filter === 'active' ? '활성 팀만 보기' : '모든 팀 보기'}
      </div>
    </div>
  );
}

 

 

경로 정보 다루기

1. params 사용 (서버 컴포넌트)

// app/products/[category]/page.tsx
export default function CategoryPage({
  params,
}: {
  params: { category: string }
}) {
  return (
    <div>
      <h1>{params.category} 카테고리</h1>
      <ProductList category={params.category} />
    </div>
  );
}

 

2. usePathname 사용 (클라이언트 컴포넌트)

// components/Navigation.tsx
'use client';
import { usePathname } from 'next/navigation';

export default function Navigation() {
  const pathname = usePathname();

  return (
    <nav>
      <Link
        href="/"
        className={pathname === '/' ? 'active' : ''}
      >
        홈
      </Link>
      <Link
        href="/products"
        className={pathname.startsWith('/products') ? 'active' : ''}
      >
        제품
      </Link>
    </nav>
  );
}

 

예시

1. 필터링과 정렬이 있는 제품 목록

// app/products/page.tsx
import { ProductList } from '@/components/ProductList';

export default function ProductsPage({
  searchParams,
}: {
  searchParams: {
    category?: string;
    sort?: string;
    page?: string;
  }
}) {
  return (
    <div className="products-page">
      <ProductList
        category={searchParams.category}
        sort={searchParams.sort}
        page={searchParams.page}
      />
    </div>
  );
}

 

2. 동적 필터 컴포넌트

// components/ProductFilter.tsx
'use client';
import { useSearchParams, useRouter } from 'next/navigation';

export default function ProductFilter() {
  const router = useRouter();
  const searchParams = useSearchParams();

  const updateFilter = (category: string) => {
    const params = new URLSearchParams(searchParams.toString());
    params.set('category', category);
    router.push(`/products?${params.toString()}`);
  };

  return (
    <div className="filter-controls">
      <button onClick={() => updateFilter('electronics')}>
        전자기기
      </button>
      <button onClick={() => updateFilter('clothing')}>
        의류
      </button>
    </div>
  );
}

 

주의사항과 모범 사례

1. 레이아웃에서의 쿼리 파라미터 접근

// ❌ 잘못된 사용
// app/layout.tsx
export default function Layout({ children }) {
  // 레이아웃에서 직접 쿼리 파라미터 접근 불가
  const searchParams = useSearchParams(); // 에러 발생!
  return <div>{children}</div>;
}

// ✅ 올바른 사용
// 필요한 정보를 자식 컴포넌트로 전달
export default function Layout({ children }) {
  return (
    <div>
      {children}
    </div>
  );
}

 

2. 성능 최적화

// components/ProductList.tsx
'use client';
import { useCallback } from 'react';
import { useSearchParams } from 'next/navigation';

export default function ProductList() {
  // searchParams 변경 감지를 위한 메모이제이션
  const getFilteredProducts = useCallback(async () => {
    const searchParams = useSearchParams();
    const filter = searchParams.get('filter');
    // 필터링 로직
  }, []);

  return <div>{/* 제품 목록 렌더링 */}</div>;
}

결론

Next.js의 레이아웃 유지 기능은 성능을 최적화하지만, 쿼리 파라미터와 경로 정보를 올바르게 관리하는 것이 중요합니다. searchParams와 useSearchParams, params와 usePathname을 적절히 활용하여 최신 상태를 유지하면서도 효율적인 애플리케이션을 구축할 수 있습니다.

728x90
반응형