
TL;DR
Next.js App Router(15+), Supabase로 진행하는 프로젝트에서 서버 컴포넌트로 작성한 헤더 내부에서 NextAuth의 useSession()을 사용하자 런타임 에러가 발생했다. SessionProvider가 필요한 클라이언트 컴포넌트를 서버 트리에서 렌더링했기 때문이었다.
해결을 위해 인증 UI 컴포넌트(로그인 버튼)만 클라이언트로 분리하고, layout.tsx에서는 <Header>와 children 모두를 <SessionProvider>로 감싸는 구조로 수정했다.
문제 상황
- 기술 스택: Next.js 15 App Router, NextAuth(Credentails), Supabase(DB전용, 인증은 NextAuth 처리)
- 목표: SSR이 가능한 <Header>를 서버 컴포넌트로 유지하면서 로그인/로그아웃 버튼은 useSession() 사용해 렌더링
- 발생한 에러:
Error: [next-auth]: `useSession` must be wrapped in a <SessionProvider />
⨯ [Error: React Context is unavailable in Server Components]
원인 분석
1. React Context는 클라이언트 컴포넌트에서만 작동
- useSession()은 SessionProvider 가 제공하는 context를 사용함
- 서버 컴포넌트인 헤더 내부에서 useSession()을 직접 호출하면 context가 존재하지 않아 오류 발생
2. SessionProvider 자체가 클라이언트 전용 컴포넌트
- layout.tsx는 기본적으로 서버 컴포넌트
- 따라서 SessionProvider를 직접 layout.tsx에 넣으면 내부적으로도 context가 전달되지 않아 에러 발생
해결
- SessionProvider를 'use client'가 선언된 클라이언트 컴포넌트(Providers.tsx)로 분리
- layout.tsx에서 Providers로 감싸되 헤더 컴포넌트와 children 모두를 포함
- 헤더는 서버 컴포넌트로 유지
- 헤더 내부의 로그인 UI만 클라이언트 컴포넌트(HeaderAuthSection.tsx)로 분리
// app/layout.tsx
<Providers>
<Header /> ← 서버 컴포넌트지만 내부에 클라 컴포넌트 있음
└── HeaderAuthSection (클라이언트, useSession() 사용)
{children}
</Providers>
// app/providers.tsx
'use client';
import { SessionProvider } from 'next-auth/react';
export function Providers({ children }: { children: React.ReactNode }) {
return <SessionProvider>{children}</SessionProvider>;
}
// components/common/Header.tsx (서버 컴포넌트)
import HeaderAuthSection from '../auth/HeaderAuthSection';
export default function Header() {
return (
<header>
<nav>...</nav>
<HeaderAuthSection />
</header>
);
}
회고
- App Router에서 서버/클라이언트 컴포넌트 분리 설계는 중요하다
- 서버 컴포넌트는 클라이언트 컴포넌트 포함 가능 (Next.js 규칙)
- 그 반대는 불가능
- 인증/세션 등 클라이언트 상태가 필요한 요소는 클라이언트 컴포넌트로 분리하기
- 결과적으로 헤더는 SSR로 유지하면서, 내부 인증 UI만 클라이언트 분리함
다음 계획
테스트 계정 로그인 기능 추가 (게스트 로그인)
'Insights > Troubleshooting' 카테고리의 다른 글
| [swimX] react-hook-form + Supabase 타입 불일치 해결하기 🛠️ (0) | 2025.04.18 |
|---|---|
| [동네zip] React 모달창 버튼 클릭 오류, 알고 보니 이벤트 버블링?! 🫧 (0) | 2025.03.05 |