본문으로 바로가기
TaeyoungKim.dev

Zustand와 React 지역 상태 차이: 장바구니 수량과 패널 열림은 어디에 둘까?

웹작성 약 3분 읽기TaeyoungKim
LinkedInX

장바구니 수량은 헤더와 상품 화면에서 함께 보여야 한다. 하지만 장바구니 패널이 열렸는지는 그 패널 버튼과 화면에서만 쓰인다. 둘 다 상태라는 이유로 한 스토어에 몰아넣으면 값의 책임이 흐려진다. 누가 그 값을 읽고 바꾸는지를 먼저 보면 Zustand 스토어와 React 지역 상태의 경계를 잡기 쉽다.

여러 화면이 공유하는 값만 스토어 후보로 본다

도식에서 패널 열림은 해당 화면 안에서 끝나지만 장바구니 수량은 여러 화면으로 이어진다. 상태 도구의 이름보다 누가 값을 읽고 수명을 관리하는지를 먼저 보면 지역 상태와 스토어의 경계를 정하기 쉽다.

다음 예제는 장바구니 수량을 여러 컴포넌트가 공유한다는 가정이다. Zustand의 create로 스토어를 만들고, 컴포넌트에서는 필요한 값이나 동작만 선택한다.

jsx
import { create } from 'zustand';
import { useState } from 'react';

const useCartStore = create((set) => ({
  count: 0,
  addOne: () => set((state) => ({ count: state.count + 1 })),
}));

function HeaderCount() {
  const count = useCartStore((state) => state.count);
  return <span>장바구니 {count}</span>;
}

function CartPanel() {
  const [open, setOpen] = useState(false);
  const count = useCartStore((state) => state.count);
  const addOne = useCartStore((state) => state.addOne);

  return (
    <section>
      <button type="button" onClick={() => setOpen((value) => !value)}>
        장바구니 {open ? '닫기' : '열기'}
      </button>
      {open && <button type="button" onClick={addOne}>한 개 추가: {count}</button>}
    </section>
  );
}

count가 바뀌면 헤더와 패널이 같은 수량을 읽는다. 반면 open은 패널의 표시 여부만 결정하므로 useState로 그 컴포넌트 가까이에 둔다. 이 값까지 무조건 전역 스토어로 옮기면 다른 화면과 공유할 필요가 없는 변경까지 공통 상태 설계에 끌어들이게 된다. 코드는 상태 위치를 설명하려는 작은 예제이며 실제 장바구니 결제 로직이 아니다.

선택자(selector)는 왜 필요한가?

useCartStore((state) => state.count)는 스토어 전체가 아니라 count를 선택한다. 교육 자료도 필요한 상태와 액션만 고르는 패턴을 강조한다. 스토어 전체를 한 번에 읽는 컴포넌트는 다른 필드가 바뀔 때도 영향을 더 쉽게 받을 수 있다. 실제 리렌더 범위는 선택 값의 동일성·컴포넌트 구조에 따라 확인해야 하므로 ‘선택자 하나면 성능 문제가 모두 해결된다’고 보지 않는다. API의 기본 형태는 Zustand 시작 문서와 맞춰 확인했다.

둘 이상의 값을 새 객체로 만들어 반환하는 선택자를 쓸 때는 반환 참조가 매번 바뀌는지도 점검한다. 성능을 이유로 모든 필드를 잘게 쪼개기 전에, 실제로 어느 컴포넌트가 자주 다시 그려지는지 측정하는 편이 낫다.

상태 위치가 잘못됐는지 어떻게 테스트할까?

상품 화면에서 수량을 올렸을 때 헤더 수량도 바뀌는지 확인한다. 패널을 닫고 다시 열어도 수량은 유지돼야 하지만, 다른 화면의 패널 열림 상태가 뜻밖에 따라 바뀌면 open의 범위가 너무 넓을 수 있다. 새로고침 뒤에도 수량을 보존해야 한다면 그것은 메모리 스토어만으로 해결되는지 별도 요구사항으로 정해야 한다. 공유와 영구 저장은 같은 개념이 아니다.

계정별 장바구니처럼 서버 데이터가 진짜 기준이라면 클라이언트 스토어만을 최종 원본으로 삼지 않는다. 서버 응답, 인증 경계, 동시 수정과 재조회 정책을 따로 설계한다. 모든 상태를 전역화하기보다, 데이터의 소유자와 수명을 먼저 정하는 것이 안전하다.

핵심 요약: 공유 범위와 수명을 먼저 정한다

여러 컴포넌트가 함께 읽는 수량은 Zustand 스토어 후보이고, 한 패널의 열림 여부는 지역 useState가 자연스럽다. 선택자로 필요한 값만 읽되, 서버 데이터와 새로고침 보존은 별개의 문제로 다룬다.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#React#Zustand#useState#전역 상태#selector

함께 읽으면 좋은 글