pile·
프론트엔드·vercel-blogVercel Blog·

Next.js App Router의 흔한 실수와 해결법

수백 명의 개발자와 수천 개의 저장소를 분석해 발견한 Next.js App Router 전환 시 흔한 실수 10가지와 해결책을 다룬다. 불필요한 Route Handler, Suspense 경계 위치 오류, "use client" 남발 등 실무에서 자주 밟는 패턴을 구체적으로 짚는다.

핵심 포인트
  • Server Component에서 Route Handler를 거치는 대신 데이터 페칭 로직을 직접 호출해 불필요한 네트워크 왕복을 없애야 한다.
  • Route Handler는 GET 메서드에서 기본값으로 빌드 타임 정적 캐싱된다. Pages Router 경험자에게 예상 외의 동작이다.
  • Client Component에서 Server Action을 직접 호출할 수 있어, 데이터 변경에 Route Handler를 별도로 만들 필요가 없다.
  • Suspense 경계는 비동기 데이터 페칭 컴포넌트 내부가 아닌 외부(상위 트리)에 배치해야 올바른 폴백 UI가 표시된다.
  • "use client" 지시어는 파일 경계를 만들어 하위 모든 컴포넌트를 Client로 만든다. 꼭 필요한 최소한의 컴포넌트에만 적용해야 한다.
  • 뮤테이션 후 캐시 갱신을 위해 revalidatePath()를 명시적으로 호출해야 한다.
상세 정리
  • 실수 1 (Route Handler + Server Component 조합): 둘 다 서버에서 실행되므로 Route Handler를 통해 요청을 보내면 불필요한 네트워크 왕복이 생긴다. 데이터 페칭 함수를 Server Component에서 직접 호출하면 된다. localhost URL 하드코딩도 흔한 실수다.
  • 실수 2 (Route Handler 캐싱 오해): GET Route Handler는 기본적으로 빌드 타임에 정적 캐싱된다. Pages Router에서 마이그레이션한 개발자가 동적 동작을 기대할 때 혼란이 생긴다. 역으로 정적 JSON 파일 프리렌더링에 활용할 수 있다.
  • 실수 3 (Client Component에 불필요한 Route Handler): Client Component에서 데이터를 변경할 때 Route Handler 대신 Server Action을 직접 호출하면 더 간결하다. 폼 제출과 이벤트 핸들러 모두에서 사용 가능하다.
  • 실수 4 (Suspense 경계 위치): 데이터를 페칭하는 컴포넌트 내부에 Suspense를 두면 의미가 없다. 페칭 컴포넌트 외부 상위 트리에 배치해야 로딩 폴백 UI가 올바르게 표시된다.
  • 실수 5 (request 객체 접근): Server Component는 request 객체에 직접 접근할 수 없다. cookies(), headers(), params, searchParams 같은 전용 함수와 props를 사용해야 한다.
  • 실수 6 (Context Provider 설정): Provider를 Client Component로 별도 분리하고 children을 받아야 Server·Client Component 혼용이 가능하다. Provider 내부에 Server Component를 children으로 넘길 수 있다.
  • 실수 7 (Server + Client Component 구성): Client Component가 Server Component를 children으로 렌더링할 수 있다. 이를 활용하면 불필요한 use client 확산을 막을 수 있다.
  • 실수 8 (use client 남발): 지시어를 추가하면 해당 파일과 모든 하위 파일이 Client 경계가 된다. 꼭 필요한 최소한의 컴포넌트에만 적용해야 Server-side 최적화를 유지할 수 있다.
  • 실수 9 (뮤테이션 후 재검증 누락): 폼 제출 후 데이터가 갱신되지 않는 문제는 revalidatePath()를 명시적으로 호출하지 않아서다. 뮤테이션 후 반드시 호출해야 캐시된 데이터가 갱신된다.
  • 실수 10 (try/catch 안에 redirect): redirect() 함수는 Next.js 내부에서 에러를 throw하는 방식으로 동작한다. try/catch 안에 두면 에러가 잡혀 리다이렉트가 실행되지 않는다. try/catch 바깥에 배치해야 한다.
왜 읽나Pages Router에서 App Router로 마이그레이션 중이거나, App Router의 데이터 페칭·캐싱·컴포넌트 구성 모델을 실무에 적용하려는 Next.js 개발자에게 실전 체크리스트로 유용하다.
vercel-blog
Vercel Blog 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·LINE EngineeringLINE Engineering·

    AI로 웹 엔지니어 없이 LINE 앱 안에서 그룹 영상 통화 서비스 만들기

    LINE Planet 팀의 PM과 Android 엔지니어 두 명이 웹 전문 엔지니어 없이 LINE 앱 내에서 그룹 영상 통화 서비스를 개발한 과정을 다룬다. LIFF(LINE Front-end Framework)와 LINE Planet SDK를 활용해 React/Vite 기반 웹 앱을 구성했고, Firebase Cloud Functions로 별도 서버 인프라 없이 구현을 완료했다.

    #react#webrtc#firebase+2