1. Why optimize navigation? (왜 네비게이션을 최적화해야하는가? )

  • 전통적인 HTML 사용법에서는 <a> 태그를 사용하여, 페이지를 연결한다.
    • /app/ui/dashboard 경로의 <NavLinks/> 컴포넌트를 살펴보면 아래와 같다.
import {
  UserGroupIcon,
  HomeIcon,
  DocumentDuplicateIcon,
} from '@heroicons/react/24/outline';

// Map of links to display in the side navigation.
// Depending on the size of the application, this would be stored in a database.
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>
        );
      })}
    </>
  );
}
  • 프로젝트 개발환경을 실행하여 클릭 이벤트를 확인해보자. 전통적인 HTML의 <a>태그는 클릭 이벤트가 발생하면, 페이지의 전체 새로고침이 일어남을 확인할 수 있을 것이다.

 

  • Next.js에서는 <Link> 컴포넌트를 사용해, 애플리케이션 내의 페이지 간의 링크를 만들 수 있다. <Link> 컴포넌트를 사용하면, JavaScript를 사용해 클라이언트 측의 탐색을 수행할 수 있다.
  • next/link에서 제공하는 <Link> 컴포넌트를 import 하여 사용할 수 있다. 아래 예제처럼 /app/ui/dashboard/nav-links.tsx 파일에서 이를 실습해보자.
    • 참고로, <Link> 컴포넌트에서 사용한 prefetchBeomy님의 포스트를 확인해보면 도움이 될 것이다.
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;
        // <a> 태그를 <Link> 컴포넌트로 변경
        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>
        );
      })}
    </>
  );
}

 

3. Automatic code-splitting and Prefetching (자동 코드분할 및 사전 패치)

  • 위의 실습을 통하여 <a>태그와 달리, <Link>컴포넌트를 사용하면, 전체 새로고침 없이 페이지 사이를 이동할 수 있음을 알 수 있을 것이다.
  • Next.js는 route segment에 따라, 애플리케이션의 코드를 자동 분할하는 방식으로 navigation 경험을 향상시킨다.
    • 이는 브라우저의 초기 로드 시, 모든 애플리케이션 코드를 로드하는 전통적인 React SPA와 다르다.
    • route별로 코드를 분할하면 페이지가 격리되며, 이 덕분에 특정 페이지에서 오류가 발생하더라도 나머지 애플리케이션 요소는 작동할 수 있게 된다.
  • Production 환경(실제 운영환경)에서는 브라우저 Viewport에 <Link>컴포넌트의 구성요소가 나타날 때마다, 연결된 route의 코드를 자동으로 백그라운드에서 Prefetch한다.
    • 사용자가 링크를 클릭할 때까지, 대상 페이지에 해당하는 코드는 이미 백그라운드에서 로드되어 있으므로, 페이지 전환이 빠르게 이루어진다.

 

  • 링크와 관련된 일반적인 UI 패턴 중 하나를 예시로 들자면, 사용자가 현재 어떤 페이지에 있는지 알려주는 활성 링크를 표시해주는 것을 언급할 수 있다.
    • 이렇게 하려면, URL에서 사용자의 현재 페이지 경로를 가져와야 한다.
  • Next.js는 현재 페이지의 경로를 확인하고, 위에서 언급한 패턴을 구현하는 데에 사용할 수 있는 hook을 지원하고 있다. 이것이 usePathname()이다.
    • usePathname()은 react-hook이기 때문에, 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";
  • 다음으로, usePathname()을 아래처럼 사용해보자.
    • 만약, /dashboard 위치에서 usePathname()을 호출했다면, 콘솔에는 '/dashboard'가 출력될 것이다.
export default function NavLinks() {
  const pathname = usePathname();
  console.log("pathname is ", pathname);

  // ...
}
  • 아래 예제코드는, links 객체 안에 있는 href의 경로와 usePathname()으로 전달받은 현재 페이지의 경로가 일치하면 clsx 라이브러리를 활용해, active css를 적용하는 코드이다.
"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";

// Map of links to display in the side navigation.
// Depending on the size of the application, this would be stored in a database.
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();
  console.log("pathname is ", pathname);
  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>
        );
      })}
    </>
  );
}
profile
프론트엔드 입문 개발자입니다.

0개의 댓글