React state vs Zustand: 전역 상태가 필요한 기준

2025.12.04·수정 2026.09.12·약 8분·작성: 해비·블로그 소개

학습 목표·선수 지식: 같은 상품 화면의 수량·장바구니·검색 URL·서버 재고를 각 소유 위치에 배치합니다. 선수 지식: props, useState, 상태 끌어올리기.

이 글에서 정리하는 내용

state가 많아졌다고 바로 Zustand를 쓰거나, 여러 컴포넌트가 공유하는 값을 계속 props로 넘기면서 구조가 복잡해지는 경우가 생깁니다. 이 글에서는 값이 어디에서 만들어지고 얼마나 멀리 공유되는지를 기준으로 useState, Context, Zustand, TanStack Query의 역할을 나눕니다.

state가 많다는 이유만으로 전역 상태가 필요한 것은 아닙니다

React 컴포넌트 안에 state가 몇 개 늘어났다는 이유만으로 상태 관리 도구가 필요한 것은 아닙니다. state 개수보다 중요한 것은 그 상태를 누가 쓰는지입니다. 버튼 하나의 열림 여부, 입력 폼의 임시 값, 카드 컴포넌트 안에서만 쓰는 선택 상태라면 useState로 충분합니다. 반대로 여러 화면이나 멀리 떨어진 컴포넌트가 같은 값을 보고 바꿔야 한다면 전역 상태를 검토할 때입니다.

useState는 가까운 화면 상태에 잘 맞습니다

모달 내부 입력값, 드롭다운 열림 여부, 탭 선택처럼 특정 컴포넌트 주변에서 끝나는 값은 useState가 가장 단순합니다. 이 값을 전역 store로 옮기면 오히려 수정 위치가 멀어집니다. React state의 기본 감각이 약하다면 React useState 사용법을 먼저 확인하는 것이 좋습니다. state는 값을 저장하는 문법이 아니라 화면 업데이트를 만드는 신호라는 점을 잡아야 합니다.

개념 부분 코드: src/components/ProductCard.tsx의 컴포넌트 전체입니다. 앱 진입점은 생략합니다.

import { useState } from 'react';
type ProductCardProps = { name: string; price: number };
export function ProductCard({ name, price }: ProductCardProps) {
  const [count, setCount] = useState(1);
  return (
    <article className="product-card">
      <h3>{name}</h3>
      <p>{price * count}원</p>
      <button type="button" onClick={() => setCount((previous) => previous + 1)}>
        수량 추가
      </button>
    </article>
  );
}
상태 선택 기준: 가까운 상태, useState, 지역 관리

props drilling은 도구보다 구조 신호로 봅니다

부모에서 자식, 손자, 더 아래 컴포넌트까지 같은 값을 계속 넘기면 props drilling이 생깁니다. 이때 무조건 Zustand로 옮기기 전에 컴포넌트 구조를 먼저 볼 필요가 있습니다. 상태를 더 가까운 부모로 옮기면 해결되는지, Context로 충분한지, 정말 여러 독립 영역에서 공유하는 값인지 확인합니다. 장바구니 수량이나 로그인 사용자 정보처럼 앱 여러 곳에서 동시에 쓰는 값이라면 전역 store가 자연스럽습니다.

Zustand는 공유 UI 상태를 작게 분리할 때 잘 맞습니다

Zustand는 store를 작게 만들고 필요한 컴포넌트에서 꺼내 쓰는 방식이 단순합니다. 여러 컴포넌트가 공유하는 필터, 사용자 설정, 장바구니 상태처럼 클라이언트 안에서 원본이 정해지는 값과 잘 맞습니다. 기본 구조는 Zustand란 무엇인가에서 확인하고, 도입 기준도 같은 글의 상태 관리 선택 기준을 함께 보면 좋습니다.

서버 상태까지 Zustand에 넣지는 않습니다

API에서 가져온 상품 목록이나 게시글 상세는 서버 상태입니다. 이런 데이터는 캐시, 재요청, 만료 시간, 에러 처리 기준이 필요하므로 TanStack Query 같은 도구가 더 잘 맞습니다. Zustand는 화면 안의 UI 상태와 사용자가 조작하는 클라이언트 상태에 집중시키는 편이 역할이 선명합니다. 값의 원본이 서버인지, 브라우저 안의 UI 판단인지 먼저 나눠보면 Zustand와 TanStack Query의 경계가 훨씬 명확해집니다.

공유 상태 관리: 공유 UI, Zustand, 전역 관리

실제로 나눌 때는 값의 이동 거리를 봅니다

상품 화면을 네 가지 소유권으로 나누기

위치와 수명확인 질문
카드 안의 주문 전 수량ProductCard의 useState, 카드 수명다른 카드의 수량도 같이 바뀌어야 하나요? 아니라면 공유하지 않습니다.
담은 상품의 수량공유 장바구니 store, 사용자 세션·저장 정책헤더와 결제 요약이 같은 수량을 보고 있나요?
적용된 검색어·페이지URL search params복사한 주소와 뒤로 가기로 같은 목록 조건이 돌아오나요?
상품 가격·재고서버와 데이터 요청 계층주문 확정 때 서버가 다시 검사하나요?

입력 중인 검색어까지 매 키 입력마다 URL이나 전역 store에 복제할 필요는 없습니다. 제출 전 초안은 로컬에 두고 적용 시 URL로 옮기는 방식도 가능합니다. 서버 상태 도구도 필수 패키지가 아니라 캐시·재검증 요구가 있을 때 선택합니다.

컴포넌트 안에서만 쓰는 값은 가까운 곳에 두는 것이 읽기 쉽습니다. 예를 들어 입력 폼의 임시 값이나 드롭다운 열림 여부는 다른 화면이 알 필요가 없습니다. 이런 값을 전역 store로 옮기면 수정할 파일이 멀어지고, 나중에 어떤 화면에서 값이 바뀌는지 추적하기 어려워집니다.

반대로 여러 컴포넌트가 같은 값을 기준으로 동시에 움직이면 이야기가 달라집니다. 헤더의 장바구니 개수, 상품 목록의 필터, 로그인 사용자 정보처럼 화면의 여러 지점이 같은 상태를 공유한다면 props로 계속 전달하는 구조가 금방 무거워집니다. 이때 Zustand 같은 store를 쓰면 값의 위치가 분명해지고, 필요한 컴포넌트만 상태를 구독하게 만들 수 있습니다.

판단할 때는 “이 값이 한 컴포넌트 안에서 끝나는가”, “형제나 멀리 떨어진 컴포넌트가 같이 쓰는가”, “새로고침 후에도 유지되어야 하는가”, “원본이 서버에 있는가”를 순서대로 확인하면 됩니다. 가까운 UI 상태는 useState, 넓게 공유하는 클라이언트 상태는 Zustand, 서버 데이터는 TanStack Query처럼 역할을 나누면 구조가 단순해집니다.

상태 관리 도구를 고르는 최종 기준

전역 상태 도구는 state가 많아서 도입하는 것이 아니라, 같은 클라이언트 상태를 멀리 떨어진 여러 컴포넌트가 함께 읽고 수정해야 할 때 도입하는 편이 자연스럽습니다. 반대로 한 화면 주변에서 끝나는 값은 가까운 곳에 두는 것이 수정하기 쉽습니다.

또한 서버에서 가져온 데이터까지 Zustand에 모으지 않는 것이 중요합니다. 서버 상태에는 캐시와 재요청, stale 처리 같은 별도 요구가 있으므로 TanStack Query와 역할을 분리하는 편이 유지보수에 유리합니다. 결국 기준은 도구 이름이 아니라 값의 원본, 공유 범위, 수명입니다.

공식 근거와 확인 범위

확인일: 2026-09-12. 실행 프로젝트는 Zustand 5.0.15, React 19.3.0, TypeScript 7.0.2로 검사했습니다. 공식 문서의 API 설명과 실제 설치 버전의 동작을 구분해 확인합니다.

이 글이 도움이 되었나요?

조회 중

Zustand 학습 순서

필수 14개 · 전체 15개

읽음 기록 관리

전체 과정 목차 (15개)
  1. 필수 길잡이 · Zustand 학습 로드맵: store·action·selector·persist 순서
  2. 필수 길잡이 · React state vs Zustand: 전역 상태가 필요한 기준 현재 글
  3. 필수 학습 · Zustand란? React 상태 관리 선택 기준과 기본 Store
  4. 필수 학습 · Zustand 설치 사용법: 기본 Store 만들고 상태 연결하기
  5. 필수 학습 · Zustand state 사용법: 값 읽기와 변경 흐름 익히기
  6. 필수 학습 · Zustand action 사용법: 상태 변경 로직을 store로 분리하기
  7. 필수 학습 · Zustand selector 사용법: 필요한 상태만 가져와 리렌더링 줄이기
  8. 필수 학습 · Zustand 리렌더링 원리와 selector 최적화 방법
  9. 필수 학습 · Zustand persist 사용법: 새로고침 후 상태 저장하기
  10. 필수 학습 · Zustand persist 마이그레이션 기준: 저장된 상태 구조가 바뀔 때
  11. 선택 참고 · Zustand 상태 변경 후 리렌더링이 안 될 때 해결 방법
  12. 필수 선수 · Zustand 실무 사용 기준: store가 복잡해질 때 피할 실수
  13. 필수 학습 · Zustand combine·immer 실습: 타입 추론과 중첩 상태 불변성
  14. 필수 학습 · Zustand subscribeWithSelector·devtools: 선택 구독과 해제 실습
  15. 필수 학습 · Zustand Todo 완성 실습: actions·선택 훅·persist 연결

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기