Next.js 13 이상부터 도입된 app 디렉토리 기반 구조는 서버 컴포넌트(Server Component)를 기본으로 채택합니다. 이로 인해 클라이언트 전용 기능인 useState, useEffect, onClick 등을 사용할 경우, 아래와 같은 오류가 발생할 수 있습니다.


에러 메시지 예시

Error: You're importing a component that needs `useState`. This React hook only works in a client component. To fix, mark the file (or its parent) with the "use client" directive.

원인 설명

Next.js의 app 디렉토리에서는 페이지나 컴포넌트 파일이 기본적으로 서버 컴포넌트로 처리됩니다. 서버 컴포넌트는 브라우저 상호작용이 필요 없는 정적/비동기 작업에 적합하지만, useState처럼 브라우저에서만 동작해야 하는 React Hook은 클라이언트 컴포넌트에서만 사용 가능합니다.


해결 방법: "use client" 지시어 추가

해당 컴포넌트 파일 최상단에 다음 줄을 추가하면 해결됩니다:

"use client";

예시 코드

"use client";

import { useState } from "react";
import { Input } from "@/components/ui/input";

export default function SignUpPage() {
  const [agree, setAgree] = useState(false);

  return (
    <div>
      <Input type="checkbox" checked={agree} onChange={() => setAgree(!agree)} />
      <label>동의합니다</label>
    </div>
  );
}

언제 "use client"를 붙여야 할까?

다음과 같은 경우, 해당 파일(혹은 그 상위 레벨 컴포넌트)은 클라이언트 컴포넌트여야 하므로 "use client"를 선언해야 합니다:

  • useState, useEffect, useRef 등 React 훅을 사용하는 경우
  • onClick, onChange 등 이벤트 핸들러를 사용하는 경우
  • 브라우저 전용 API(window, localStorage 등)를 사용하는 경우

참고 사항

  • "use client"는 해당 파일에만 적용됩니다. 하위 컴포넌트에는 자동으로 전파되지 않습니다.
  • 가능하면 클라이언트 기능은 최소한의 파일에서만 분리해 사용하는 것이 SSR 최적화에 유리합니다.

정리

Next.js의 서버 중심 아키텍처는 성능과 최적화에 강점이 있지만, 사용자 인터랙션을 구현하려면 클라이언트 컴포넌트가 필요합니다. "use client" 지시어는 이를 선언하는 방식이며, 이 구조를 이해하면 더욱 효율적인 Next.js 프로젝트 구성이 가능합니다.

Next.js는 파일 기반 라우팅(file-based routing) 시스템을 채택하고 있습니다. 이는 기존의 React Router처럼 별도 설정 없이, 폴더 구조만으로 자동으로 라우팅이 구성되는 방식입니다.

1. 기본 라우팅

src/app/page.jsx → /
src/app/about/page.jsx → /about
src/app/login/page.jsx → /login

각 디렉토리 안에 있는 page.jsx 파일이 해당 URL 경로와 매핑됩니다.

2. 동적 라우팅

Next.js에서는 대괄호([param]) 문법으로 동적 라우팅이 가능합니다.

src/app/posts/[id]/page.jsx → /posts/1, /posts/abc 등 다양한 id 값 허용

3. 중첩 라우트

디렉토리를 중첩시켜 라우트를 구성할 수 있습니다. 각 디렉토리에서 layout.jsx를 정의하면 해당 경로 이하의 모든 하위 페이지에 공통 레이아웃을 적용할 수 있습니다.

4. API 라우트

src/app/api/hello/route.js → /api/hello

Next.js는 API 라우팅을 위한 구조도 제공합니다. 간단한 백엔드 기능을 이 구조로 함께 개발할 수 있습니다.

5. 기타 관련 파일들

  • layout.jsx: 공통 레이아웃 정의
  • loading.jsx: 로딩 중 화면 정의
  • error.jsx: 에러 발생 시 렌더링할 컴포넌트
  • head.jsx: <head> 메타 태그 커스터마이징

결론

Next.js의 라우팅은 매우 직관적이며 유지보수에 강합니다. 코드를 분리하고 관리하기 좋으며, 디렉토리 구조만으로도 복잡한 웹페이지의 구성과 흐름을 명확하게 표현할 수 있습니다. 이는 규모가 커질수록 더욱 진가를 발휘합니다.

 

웹 프론트엔드 개발을 시작할 때 수많은 프레임워크와 라이브러리 중 어떤 것을 선택할지 고민하게 됩니다. React, Vue, Angular, Svelte 등 다양한 선택지가 있지만, 최근에는 Next.js가 압도적으로 주목받고 있습니다. 왜 그런지, 그리고 왜 나 역시 Next.js를 선택했는지를 공유하고자 합니다.

✅ React 위에서 동작하는 프레임워크

Next.js는 React를 기반으로 만들어졌기 때문에 기존에 React를 알고 있다면 진입 장벽이 낮습니다. 순수 React만으로 프로젝트를 구성하면 라우팅, SSR(서버사이드 렌더링), SEO 최적화 등을 직접 처리해야 합니다. 반면, Next.js는 이런 부분을 프레임워크 수준에서 기본 제공합니다.

✅ 서버 사이드 렌더링(SSR) & 정적 생성(SSG) 지원

SEO에 민감한 웹페이지(예: 블로그, 쇼핑몰 등)에서는 SSR이 매우 중요합니다. Next.js는 getServerSideProps, getStaticProps 등을 통해 페이지를 서버에서 렌더링하거나 빌드시 미리 생성할 수 있게 해줍니다. 이는 React가 SPA(Single Page Application)로서 갖는 SEO 한계를 극복합니다.

✅ 파일 기반 라우팅 + API 라우트

Next.js는 디렉토리 구조만으로 라우팅을 구성할 수 있어 직관적이며 유지보수가 쉽습니다. 또, /api 디렉토리를 통해 API 라우트를 구성할 수 있어 간단한 백엔드 기능까지 포함한 풀스택 개발이 가능합니다.

✅ Fullstack에 가까운 생산성

Next.js는 Vercel이라는 호스팅 플랫폼과도 잘 통합되어 있으며, 프론트엔드와 백엔드를 함께 관리할 수 있는 Fullstack 개발 환경을 지향합니다. Rust, Go, Express 등의 백엔드 언어나 프레임워크도 뛰어나지만, Next.js는 프론트 중심의 프로젝트를 빠르게 진행할 수 있게 해줍니다.

✅ TypeScript, ESLint, Tailwind 등과의 높은 호환성

Next.js는 초기 설정만으로도 TypeScript, ESLint, Prettier, Tailwind CSS 등의 툴을 자동으로 통합할 수 있어, 현대적 개발 환경을 구축하는 데 매우 유리합니다.

결론

React를 잘 알고 있다면, 그리고 빠르게 프론트엔드와 SSR을 적용한 웹페이지를 만들고 싶다면 Next.js는 매우 매력적인 선택지입니다. Rust나 다른 백엔드 프레임워크가 뛰어난 퍼포먼스를 제공할 수는 있지만, 웹의 빠른 개발과 배포, 사용자 경험을 생각하면 Next.js가 가진 강점은 분명합니다.

+ Recent posts