Next.js 네비게이션 최적화 완벽 가이드

🤔 왜 네비게이션을 최적화해야 할까?

전통적인 HTML 방식의 문제점

일반적인 HTML에서는 <a> 태그를 사용하여 페이지를 연결합니다. 하지만 이 방식은 전체 페이지 새로고침이라는 치명적인 단점이 있습니다.

// /app/ui/dashboard/nav-links.tsx
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';

const links = [
  { name: 'Home', href: '/dashboard', icon: HomeIcon },
  { name: 'Invoices', href: '/dashboard/invoices', icon: DocumentDuplicateIcon },
  { name: 'Customers', href: '/dashboard/customers', icon: UserGroupIcon },
];
  
export default function NavLinks() {
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <a
            key={link.name}
            href={link.href}
            className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </a>
        );
      })}
    </>
  );
}

⚠️ 문제점: 링크 클릭 시 전체 페이지 새로고침 발생


클라이언트 사이드 네비게이션의 강력함

Next.js의 <Link> 컴포넌트는 JavaScript 기반 클라이언트 사이드 네비게이션을 제공하여 사용자 경험을 크게 향상시킵니다.

// /app/ui/dashboard/nav-links.tsx
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';
import Link from 'next/link'; // 추가

const links = [
  { name: 'Home', href: '/dashboard', icon: HomeIcon },
  { name: 'Invoices', href: '/dashboard/invoices', icon: DocumentDuplicateIcon },
  { name: 'Customers', href: '/dashboard/customers', icon: UserGroupIcon },
];

export default function NavLinks() {
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            prefetch={false}
            className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

💡 Prefetch 참고자료: Beomy님의 preload, preconnect, prefetch 포스트에서 자세한 내용을 확인할 수 있습니다.


🚀 자동 코드 분할 & Prefetching

React SPA vs Next.js의 차이점

❌ 전통적인 React SPA

  • 초기 로드 시 모든 애플리케이션 코드를 한 번에 로드
  • 무거운 초기 로딩 시간
  • 하나의 번들 파일에 모든 코드 포함

✅ Next.js의 혁신적 접근

  • Route Segment별 자동 코드 분할
  • 페이지별 격리된 코드 구조
  • 특정 페이지 오류 시에도 다른 페이지는 정상 작동

🔄 Smart Prefetching 시스템

Production 환경에서의 동작:
1. 브라우저 Viewport에 <Link> 컴포넌트가 나타남
2. 연결된 route의 코드를 백그라운드에서 자동 Prefetch
3. 사용자가 링크 클릭 시 이미 로드된 코드로 즉시 전환

결과:초고속 페이지 전환 실현


🎯 활성 링크 표시 패턴

사용자 경험을 위한 필수 패턴

사용자가 현재 어떤 페이지에 있는지 명확하게 알려주는 활성 링크 표시는 필수적인 UI 패턴입니다.

usePathname Hook 활용

1단계: 클라이언트 컴포넌트로 전환

// /app/ui/dashboard/nav-links.tsx
"use client"; // 클라이언트 컴포넌트 선언

import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from "@heroicons/react/24/outline";
import clsx from "clsx";
import Link from "next/link";
import { usePathname } from "next/navigation"; // 추가

2단계: 현재 경로 감지

export default function NavLinks() {
  const pathname = usePathname();
  console.log("pathname is ", pathname); // 현재 경로 출력
  
  // 예: '/dashboard'에서 호출 시 → '/dashboard' 출력
}

3단계: 조건부 스타일링 구현

"use client";

import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from "@heroicons/react/24/outline";
import clsx from "clsx";
import Link from "next/link";
import { usePathname } from "next/navigation";

const links = [
  { name: "Home", href: "/dashboard", icon: HomeIcon },
  { name: "Invoices", href: "/dashboard/invoices", icon: DocumentDuplicateIcon },
  { name: "Customers", href: "/dashboard/customers", icon: UserGroupIcon },
];

export default function NavLinks() {
  const pathname = usePathname();
  
  return (
    <>
      {links.map((link) => {
        const LinkIcon = link.icon;
        return (
          <Link
            key={link.name}
            href={link.href}
            className={clsx(
              "flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3",
              {
                // 현재 경로와 링크 경로가 일치하면 활성 스타일 적용
                "bg-sky-100 text-blue-600": pathname === link.href,
              }
            )}
          >
            <LinkIcon className="w-6" />
            <p className="hidden md:block">{link.name}</p>
          </Link>
        );
      })}
    </>
  );
}

🎨 활성 스타일 분석

기본 스타일

"bg-gray-50 text-gray-800" /* 비활성 상태 */

활성 스타일

"bg-sky-100 text-blue-600" /* 활성 상태 */

Hover 스타일

"hover:bg-sky-100 hover:text-blue-600" /* 호버 상태 */

📊 최적화 효과 비교

구분전통적인 <a> 태그Next.js <Link>
페이지 전환전체 새로고침부분 업데이트
로딩 속도느림초고속
코드 분할없음자동 분할
Prefetching없음자동 실행
사용자 경험끊김매끄러움

🔑 핵심 포인트

Next.js 네비게이션의 4가지 핵심 기능

  1. 🔄 클라이언트 사이드 라우팅: 페이지 새로고침 없는 부드러운 전환
  2. 📦 자동 코드 분할: Route별 효율적인 코드 관리
  3. ⚡ Smart Prefetching: 백그라운드에서 미리 로드
  4. 🎯 활성 링크 감지: usePathname을 통한 현재 위치 표시

Next.js의 네비게이션 시스템을 활용하면 성능과 사용자 경험을 동시에 최적화할 수 있습니다.

profile
프론트엔드 입문 개발자입니다.

0개의 댓글