AI Store에서 AI코딩으로 만들어진 앱을 만나보세요!
지금 바로 방문하기

React의 `useSyncExternalStore` 실전 활용: 탭 간 쇼핑 카트 구현

카테고리

프로그래밍/소프트웨어 개발

서브카테고리

웹 개발

대상자

  • React 개발자 (중급 이상): 상태 동기화, 탭 간 데이터 공유, SSR 호환성 문제 해결에 관심 있는 분
  • 난이도: 중급 (React Hooks, 상태 관리, 콘커런시 이해 필요)

핵심 요약

  • useSyncExternalStore의 핵심 기능:
  • localStorage 기반 탭 간 상태 동기화 (StorageEvent 활용)
  • 콘커런시 안전한 렌더링 (렌더링 중 상태 변화 시 snapshot 동기화)
  • SSR 호환성 해결 (getServerSnapshot 옵션 제공)
  • 구현 핵심 코드:
  • cartStore에서 getSnapshot, subscribe 메서드 정의 (StorageEvent 리스너 연결)
  • useSyncExternalStore를 통해 React 컴포넌트에서 외부 상태를 읽음
  • useCart 커스텀 훅으로 useSyncExternalStore를 캡슐화
  • 비교 우위:
  • useEffect + useState 방식보다 메모리 누수 방지, 하이드레이션 경고 제거, 동기화 안정성 향상

섹션별 세부 요약

1. 문제 정의: React 18의 콘커런시와 외부 상태 동기화의 어려움

  • Tearing 문제: 탭 간 상태 변경 시 DOM 일관성 손상
  • SSR 하이드레이션 불일치: 서버와 클라이언트 상태 불일치로 인한 경고 발생
  • 구독 로직 중복: 각 컴포넌트가 별도 useEffect로 이벤트 리스너 추가

2. `useSyncExternalStore` 활용한 탭 간 쇼핑 카트 구현

  • cartStore.ts 설계:
  • readCart()/writeCart() 함수로 localStorage와의 상호작용 정의
  • StorageEvent를 통해 탭 간 상태 변경 알림
  • getSnapshot, subscribe 메서드를 useSyncExternalStore에 전달
  • useCart.ts에서의 적용:
  • useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) 호출
  • 서버에서 getServerSnapshot을 통해 초기 상태 로드

3. `useSyncExternalStore` vs. `useEffect + useState` 비교

  • useEffect 기반 접근의 단점:
  • Tearing 가능성: 콘커런시 렌더링 중 상태 불일치
  • 리스너 중복 생성: 각 컴포넌트별 이벤트 리스너 추가
  • SSR 하이드레이션 문제: 서버/클라이언트 상태 불일치 시 경고 발생
  • useSyncExternalStore의 장점:
  • 자동 구독/구독 해제: 리스너 관리 최소화
  • 하이드레이션 경고 제거: getServerSnapshot으로 서버 상태 동기화
  • 동일한 snapshot 사용: 렌더링 중 모든 컴포넌트가 동일한 상태 읽음

4. 확장성과 활용 사례

  • 다양한 외부 상태 소스 지원: Redux, WebSocket, matchMedia 등과 호환
  • 아키텍처 패턴:
  • subscribegetSnapshot 인터페이스만 변경하면 상태 소스 교체 가능
  • localStorage 대신 Redux로 교체 시 subscribe 메서드 재구현

결론

  • 실무 적용 팁:
  • useSyncExternalStore를 사용하여 외부 상태 동기화 로직의 복잡성과 오류 위험을 줄임
  • 타브 간 상태 공유StorageEvent와 결합하여 실시간 업데이트 구현
  • SSR 환경에서는 getServerSnapshot을 반드시 정의하여 하이드레이션 문제 방지
  • 핵심 메시지: useSyncExternalStore는 React의 선언적 세계와 외부 상태 간의 격차를 해소하는 최소한의 API로, 탭 간 상태 공유, SSR 호환성, 콘커런시 안정성 문제를 한 번에 해결 가능.