들어가며#
Next.js 15와 React 19 환경에서 상태를 관리하는 방식은 서버 컴포넌트의 등장으로 기존과는 완전히 다른 접근이 필요한데요.
이번 글에서는 다양한 유스케이스별로 가장 최적화된 상태 관리 구현 방법을 자세히 알아볼 것입니다.
기본 방침#
Next.js 15와 React 19에서 상태를 관리할 때 따라야 할 세 가지 핵심 원칙이 있는데요.
이 원칙들을 기준으로 삼으면 복잡한 상태 관리 문제도 명쾌하게 해결할 수 있습니다.
1. 원격 데이터는 서버 데이터 스냅샷과 서버 상태로 관리#
서버에서 가져온 데이터(Remote Data)는 서버 데이터 스냅샷과 서버 상태라는 개념으로 관리해야 하거든요.
기존처럼 전역 상태(Global State)에 데이터를 저장하는 방식에서 벗어나, 각 화면에서 필요할 때마다 fetch하고 캐시를 활용하는 것이 핵심입니다.
2. 전역 상태는 최대한 사용하지 않기#
전역 상태는 가능한 한 사용하지 않는 것이 좋은데요.
1번 원칙으로 해결할 수 없는, 클라이언트 고유의 데이터에 한해서만 소규모/중규모 전역 상태 도입을 신중하게 검토합니다.
전역 상태는 불필요한 리렌더링을 유발하고 코드를 복잡하게 만들어 디버깅을 어렵게 만들기 때문에 정말 신중하게 사용해야 합니다.
3. 데이터의 주인(SSOT)과 범위(Scope)를 기준으로 선택#
데이터의 진짜 주인(SSOT, Single Source of Truth)이 누구인지, 그리고 그 데이터가 어디까지 필요한지(Scope)를 기준으로 상태 관리 방식을 선택해야 하는데요.
데이터의 주인이 서버인지 클라이언트인지, 또 단일 컴포넌트에서만 쓰이는지 여러 화면에서 쓰이는지를 명확히 하면, 가장 적절한 방법을 선택할 수 있습니다.
유스케이스와 구현 방법#
상태 관리의 주요 유스케이스와 각 상황에 맞는 최적의 구현 방법을 정리해봤는데요.
하나씩 자세히 살펴보겠습니다.
| 유스케이스 | 카테고리 | 구현 방법 |
|---|---|---|
| 1 | 클라이언트 데이터 + 단일 컴포넌트 | 로컬 상태 |
| useState, useReducer | ||
| 2 | 클라이언트 데이터 + 여러 컴포넌트/화면 | 소규모/중규모 전역 상태 |
| useContext, Zustand, Jotai | ||
| 3 | 대규모 앱 + 복잡한 전역 상태 | 대규모 전역 상태 |
| Redux Toolkit | ||
| 4 | 원격 데이터 + 서버 로딩 | 서버 데이터 스냅샷 |
| 서버 컴포넌트 + fetch + 데이터 캐시 | ||
| 5 | 원격 데이터 + 클라이언트 로딩 | 서버 상태 |
| TanStack Query | ||
| 6 | 현재 상태의 재현/공유/유지 | URL 상태 |
| searchParams/useSearchParams + Link/router.replace | ||
| 7 | 입력값/유효성 검사 관리 | 폼 상태 |
| React Hook Form, useActionState 등 + zod | ||
| 8 | 세션/탭 간 공유, 오프라인 캐시 | 브라우저 상태 |
| localStorage, sessionStorage, IndexedDB | ||
| 9 | 사용자 식별 + 민감 정보 | 세션 / 인증 상태 |
| httpOnly Cookie, Redis |
그럼, 각 유스케이스에 대해 더 자세히 알아보겠습니다.
1. 클라이언트 데이터 + 단일 컴포넌트 (로컬 상태)#
useState나 useReducer를 사용해 단일 컴포넌트 안에서만 사용하는 클라이언트 전용 상태를 관리하는 패턴인데요.
데이터베이스에 저장할 필요 없이 컴포넌트가 사라지면 함께 사라지는 임시적인 UI 상태를 다룰 때 사용합니다.
모달의 열림/닫힘 상태, 탭 선택 상태 등이 대표적인 예시인데요.
기본적으로는 useState를 사용하지만, 여러 상태가 서로 맞물려 복잡하게 업데이트된다면 useReducer를 쓰는 것이 코드를 더 깔끔하게 만들어줍니다.
2. 클라이언트 데이터 + 여러 컴포넌트/화면 (소규모/중규모 전역 상태)#
여러 컴포넌트나 화면에 걸쳐 공유해야 하는 클라이언트 전용 상태를 관리하는 패턴인데요.
검색 조건, 테마 설정, 토스트 알림처럼 여러 곳에서 함께 사용하고 업데이트해야 하는 상태에 적합합니다.
useContext, Zustand, Jotai 등을 활용해 필요한 범위만큼만 전역 상태를 관리하거든요.
테마처럼 자주 바뀌지 않는 값은 useContext로 충분하지만, 업데이트가 잦은 상태는 부분 구독(Partial Subscription) 기능으로 불필요한 리렌더링을 막아주는 Zustand나 Jotai가 더 유리합니다.
3. 대규모 앱 + 복잡한 전역 상태 (대규모 전역 상태)#
아주 큰 규모의 엔터프라이즈급 애플리케이션에서 여러 도메인에 걸친 복잡한 상태를 중앙에서 엄격하게 관리해야 할 때 사용하는 패턴인데요.
다만 Next.js 15 / React 19에서는 서버 컴포넌트, TanStack Query, Zustand 조합으로 대부분의 유스케이스에 대응할 수 있기 때문에, 기본적으로 대규모 전역 상태 관리는 필요하지 않습니다.
4. 원격 데이터 + 서버 로딩 (서버 데이터 스냅샷)#
첫 화면을 렌더링할 때 서버 컴포넌트에서 데이터를 미리 가져오고, 그 결과물(스냅샷) 자체를 일종의 상태로 취급하는 패턴인데요.
Next.js 15의 데이터 캐시(Data Cache)를 활용하면 가져온 데이터를 서버에 저장해두고, 두 번째 요청부터는 캐시에서 빠르게 응답할 수 있습니다.
Next.js 15에서는 이 방식이 원격 데이터를 다루는 가장 기본적인 최우선 전략이거든요.
여러 컴포넌트에서 같은 데이터가 필요하면, 각자 같은 API를 호출하기만 하면 데이터 캐시가 알아서 효율적으로 데이터를 재사용해줍니다.
5. 원격 데이터 + 클라이언트 로딩 (서버 상태)#
사용자의 행동을 계기로 클라이언트에서 데이터를 가져오고, 그 상태를 TanStack Query로 관리하는 패턴인데요.
검색 결과, 필터링, 무한 스크롤처럼 사용자의 상호작용에 따라 동적으로 데이터를 가져올 때 사용합니다.
TanStack Query는 강력한 캐시 기능을 내장하고 있거든요.
따라서 여러 컴포넌트에서 같은 queryKey를 사용하면 자동으로 캐시가 공유되어 불필요한 API 요청을 막아줍니다.
6. 현재 상태의 재현/공유/유지 (URL 상태)#
사용자의 조작 상태를 URL 파라미터에 담아서, 페이지를 새로고침하거나 URL을 공유해도 현재 상태가 그대로 유지되도록 만드는 패턴인데요.
검색 조건, 페이지네이션, 탭 선택 상태처럼 다른 사람과 공유하거나 나중에 다시 보고 싶은 상태를 관리할 때 아주 유용합니다.
서버 컴포넌트에서는 searchParams로, 클라이언트 컴포넌트에서는 useSearchParams로 URL 파라미터를 읽고, Link나 router.replace 등으로 URL을 업데이트하거든요.
만약 서버 컴포넌트를 다시 렌더링하고 싶지 않다면, history.replaceState를 사용해 URL만 조용히 업데이트하는 방법도 있습니다.
7. 입력값/유효성 검사 관리 (폼 상태)#
폼(Form)의 입력값과 유효성 검사 결과를 관리하는 패턴인데요.
React Hook Form, useState, useActionState 같은 도구들을 zod와 함께 사용하면 타입까지 안전한 폼을 손쉽게 만들 수 있습니다.
항목이 많은 복잡한 폼은 React Hook Form이 유리한데요.
간단한 폼은 useState나 서버 액션과 연동이 쉬운 useActionState만으로도 충분합니다.
8. 세션/탭 간 공유, 오프라인 캐시 (브라우저 상태)#
브라우저 저장소(localStorage, sessionStorage, IndexedDB)를 사용해 클라이언트 전용 상태를 브라우저에 영구적으로 저장하는 패턴인데요.
페이지를 새로고침해도 상태가 유지되고, 다른 탭과 상태를 공유하거나 오프라인 상태에서도 동작하는 기능을 만들 수 있습니다.
테마나 언어 설정처럼 영구적인 정보는 localStorage에, 현재 세션에서만 유효한 임시 정보는 sessionStorage에 저장하거든요.
대용량 데이터나 복잡한 구조의 데이터를 다루거나 오프라인 지원이 필요하다면, 비동기 API인 IndexedDB를 사용하는 것이 좋습니다.
9. 사용자 식별 + 민감 정보 (세션/인증 상태)#
사용자 인증 정보나 세션 데이터처럼 보안이 중요한 민감 정보를 안전하게 관리하는 패턴인데요.
httpOnly 속성이 부여된 쿠키(Cookie)를 사용하면 자바스크립트(JavaScript)로 접근할 수 없게 되어, XSS 같은 공격으로부터 토큰이나 세션 ID를 안전하게 보호할 수 있습니다.
이 쿠키를 서버 측에서만 읽고 검증하는 방식으로 보안을 강화하거든요.
Redis 같은 외부 세션 저장소와 함께 사용하면 더욱 견고한 인증 시스템을 구축할 수 있습니다.
마치며#
이번 글에서는 Next.js 15와 React 19 환경에서 상태를 관리하는 다양한 방법들을 유스케이스별로 알아봤는데요.
상태 관리는 애플리케이션 설계의 가장 핵심적인 부분 중 하나입니다.
데이터의 주인(SSOT)과 범위(Scope)를 명확히 구분하고, 각 상황에 맞는 최적의 상태 관리 도구를 선택하는 것이 유지보수성과 확장성을 높이는 열쇠거든요.
특히, 원격 데이터는 더 이상 전역 상태로 관리하지 않고, 서버 컴포넌트나 TanStack Query를 적극 활용하는 것이 Next.js 15 / React 19 시대의 상태 관리 핵심이라는 점을 기억해야 합니다.
끝까지 읽어주셔서 정말 감사합니다.