TestForge | Aidevops | 📊 Plogger ✍️ Blog 📚 Docs
plogger

AI DevOps Korea

AI 서비스 개발, 운영, 성능개선을 하나의 루프로 연결합니다

aidevops.kr에서 LLMOps, RAG, AI Agent, 관측성, 평가, 비용-성능 최적화를 실전 운영 관점으로 정리합니다.

React 상태관리 전략 가이드

· 수정 4월 17일
아키텍처 다이어그램
이 글에서 다루는 핵심 흐름, 아키텍처 구조, 주요 판단 포인트를 한눈에 이해할 수 있도록 정리한 그림입니다.
# React 상태관리 전략 가이드

React에서 상태관리는 기술 선택 논쟁으로 흐르기 쉽다. Context를 쓸지, Zustand를 쓸지, Redux를 쓸지, TanStack Query를 함께 쓸지에 관심이 몰리지만, 실제로 더 중요한 문제는 상태의 종류와 책임을 먼저 구분하는 일이다. 좋은 상태관리 전략은 라이브러리 조합보다 “어떤 상태를 누가 소유하고 언제 동기화할 것인가”를 명확히 한다.

아키텍처 그림 설명

[URL State]        [Server State]
 filters/page      cache/query data
      |                 |
      +--------+--------+
               v
         [Feature State]
      checkout / editor / flow
               |
               v
           [Local UI State]
      input / modal / hover / draft

상태 전략은 보통 위에서 아래로 내려갈수록 수명이 짧아집니다. URL 상태는 복원성과 공유 가능성이 중요하고, 서버 상태는 최신성과 캐시 규칙이 중요하며, 기능 상태는 비즈니스 흐름을 표현합니다. 이 층을 나누지 않으면 모든 값이 전역 스토어로 몰리거나 반대로 화면마다 중복 로직이 생깁니다.

상태는 하나가 아니라 여러 층이다

React 애플리케이션에는 보통 다음 네 층의 상태가 존재한다.

  • 로컬 상태: 단일 컴포넌트 안에서만 의미가 있는 입력값과 UI 상호작용
  • 전역 UI 상태: 모달, 토스트, 테마, 네비게이션 열림 여부
  • 서버 상태: API 응답, 목록 데이터, 상세 조회, 캐시와 재검증 대상
  • 도메인 상태: 장바구니, 편집 흐름, 다단계 작업, 임시 저장 중인 비즈니스 데이터

이 네 층을 구분하지 않으면 Context에 모든 것을 넣거나, 반대로 전역 스토어 하나가 데이터베이스처럼 커진다. 어느 쪽이든 변경 영향 범위가 넓어지고 디버깅이 어려워진다.

Context는 공유 메커니즘이지 만능 상태 저장소가 아니다

React Context는 가벼운 공유에는 유용하지만, 빈번하게 변하는 상태나 복잡한 서버 데이터를 모두 맡기기에는 한계가 있다. Context는 “어디서든 접근 가능함”을 쉽게 만들지만, 그만큼 성능과 구조를 잘못 설계하면 전체 트리에 영향을 주기 쉽다.

실무에서는 Context를 다음 용도로 제한하는 것이 안정적이다.

  • 인증된 사용자 최소 정보
  • 테마나 로케일 같은 전역 설정
  • 의존성 주입 성격의 서비스 접근 포인트

반대로 자주 바뀌는 엔티티 컬렉션이나 대규모 폼 상태, 서버 캐시는 Context만으로 해결하려 들지 않는 편이 낫다.

서버 상태는 별도의 문제로 다뤄야 한다

React 프로젝트가 복잡해질수록 가장 먼저 분리해야 하는 것은 서버 상태다. 원격 데이터는 로컬 상태와 다르게 최신성, 중복 요청, 로딩, 실패, 재시도, 캐시 무효화 문제가 따라온다. 이 문제를 단순 useStateuseEffect 조합으로만 처리하면 곧 코드가 흩어진다.

서버 상태는 다음 기준으로 다뤄야 한다.

  • 캐시 키가 명확한가
  • 언제 stale로 볼 것인가
  • 어떤 액션 후 어떤 조회가 무효화되는가
  • optimistic update를 허용할 것인가
  • 사용자 전환이나 권한 변경 시 어떤 데이터를 폐기할 것인가

이는 전역 상태 라이브러리보다 서버 상태 라이브러리나 전용 데이터 계층이 더 잘 해결하는 영역이다.

전역 상태는 “여러 화면이 진짜로 공유하는가”로 판단하라

많은 팀이 상태를 전역으로 올리는 이유는 “나중에 다른 데서도 쓸 수 있을 것 같아서”다. 하지만 실제로는 대부분의 상태가 특정 기능 안에서만 의미를 가진다. 이를 섣불리 중앙화하면 추적이 어려워지고, 예기치 않은 리렌더와 의존성이 늘어난다.

전역 상태로 올릴 가치가 있는 것은 보통 다음과 같다.

  • 로그인 세션과 권한 정보
  • 앱 전체에서 지속되는 사용자 작업 컨텍스트
  • 여러 화면에서 동시에 접근해야 하는 도메인 상태
  • 전역 UI 제어 정보

이 기준에 맞지 않으면 기능 내부에 남겨 두는 편이 더 낫다.

도메인 상태는 비즈니스 흐름 중심으로 묶어라

장바구니, 예약 흐름, 편집 세션, 업로드 큐처럼 비즈니스적으로 의미가 있는 상태는 단순 UI 상태와 다르다. 이들은 여러 화면을 가로지르기도 하고, 검증 규칙이나 파생 계산이 존재하며, 종종 저장과 복원 전략도 필요하다.

따라서 도메인 상태는 modalStore 같은 기술 이름보다 checkoutState, editorSession, uploadQueue처럼 비즈니스 이름을 갖는 것이 구조적으로 낫다. 이름이 곧 책임을 드러내기 때문이다.

URL, 상태, 화면 복원력을 함께 설계하라

필터, 정렬, 검색어, 페이지 번호, 선택 탭처럼 사용자가 새로고침하거나 링크로 공유했을 때 복구되길 기대하는 정보는 상태 라이브러리만으로 관리하면 안 된다. 이런 정보는 URL과 동기화하는 편이 더 자연스럽다.

반대로 일시적인 애니메이션 상태나 hover 상태를 URL로 올리는 것은 과하다. 중요한 것은 “이 상태가 사용자 맥락을 복원하는 데 필요한가”를 기준으로 판단하는 것이다.

성능 문제는 상태의 위치에서 시작된다

React 성능 이슈는 종종 렌더링 최적화 기법의 문제처럼 보이지만, 실제로는 상태가 잘못된 위치에 놓였기 때문에 발생한다. 너무 상위에 둔 상태는 불필요한 리렌더를 만들고, 지나치게 중앙화된 전역 상태는 사소한 변경도 넓은 트리에 영향을 준다.

따라서 성능 관점에서도 중요한 질문은 다음이다.

  • 이 상태를 정말 상위에서 소유해야 하는가
  • 이 값은 파생 계산으로 대체할 수 없는가
  • 구독 범위를 더 좁힐 수 없는가
  • 서버 상태를 클라이언트 전역 상태로 복사하고 있지는 않은가

자주 생기는 안티패턴

  • useEffect 기반 fetch 결과를 전역 스토어에 계속 복사함
  • Context 하나에 설정, 사용자, 데이터 캐시, UI 상태를 모두 담음
  • 로컬 폼 상태까지 중앙화해서 작은 수정도 전역 영향을 줌
  • URL이 가져야 할 검색/필터 상태를 메모리 안에만 둠
  • 상태 소유권이 불명확해 같은 데이터가 여러 저장소에 중복 존재함

마무리

React 상태관리 전략의 핵심은 어떤 라이브러리를 쓰는가보다, 상태의 성격과 수명주기, 공유 범위, 최신성 규칙을 명확히 나누는 것이다. 상태를 한곳에 모으는 것은 통제처럼 보이지만, 실제로는 결합도를 높여 시스템을 더 취약하게 만들 수 있다.

좋은 React 아키텍처는 전역 상태가 많은 앱이 아니라, 필요한 상태만 정확한 위치에 놓여 있는 앱이다.

운영 환경에서 어려워지는 지점

  • React에서 로컬 UI 상태, 서버 캐시, 폼 상태, 워크플로우 상태가 섞이기 시작하면 상태 전략이 급격히 어려워진다.
  • 팀이 실패하는 이유는 대개 “잘못된 라이브러리”를 골라서가 아니라 상태 소유권 규칙을 정하지 않았기 때문이다.
  • 초기에 편해 보이는 전역 상태는 가장 큰 숨은 결합 지점이 되기 쉽다.

중요한 아키텍처 결정

  • 일시적인 뷰 상태는 정말 여러 떨어진 기능이 함께 써야 할 때가 아니면 로컬에 둔다.
  • 공유 클라이언트 상태는 Context + reducer, Zustand, Jotai 또는 Redux Toolkit가 명확한 소유권과 재사용 가치를 줄 때만 둔다.
  • 서버에서 온 데이터는 자체 캐시와 invalidation 정책을 가진 서버 상태로 다룬다.

실무 예시

안정적인 전략은 보통 상태를 출처와 수명 기준으로 구분한다.

local state -> 모달 열림, 입력 draft, 탭 선택
server state -> 가져온 목록, 프로필 요약, 권한
workflow state -> 체크아웃 진행, 위저드 draft
shared client state -> 테마, 인증 세션, feature flag

피해야 할 안티패턴

  • 반복된다는 이유만으로 모든 값을 전역 상태로 올리는 것.
  • 접근이 편하다는 이유로 서버 캐시를 클라이언트 store에 복제하는 것.
  • 상태 계층이 해결해야 할 문제를 정의하기 전에 도구부터 고르는 것.

운영 체크리스트

  • 로컬, 공유, 서버 상태의 소유권 규칙을 문서화한다.
  • 기능이 늘 때 전역 store가 줄어드는지 커지는지 검토한다.
  • 재렌더링 비용과 stale state 사고를 측정한다.
  • 화면 간 workflow의 optimistic update와 rollback 동작을 테스트한다.

최종 판단

React 상태 관리는 상태를 서로 다른 아키텍처 클래스들로 다룰 때 잘 작동한다. 모든 것을 하나의 store에 넣는 전략은 결국 모든 복잡성을 한곳에 모은다.

Continue Reading

다음으로 읽기 좋은 글

다음 탐색

이 주제를 시스템 관점으로 더 이어서 보기