Files
frontend/docs/st/05.상태관리.md

4.6 KiB

05. 상태 관리

ST 앱의 상태 관리 전략과 Zustand 기반 전역 상태 설계를 설명합니다.


1. 상태 관리 전략 개요

ST 앱은 상태의 **성격(클라이언트 vs 서버)**에 따라 다른 도구를 사용합니다.

┌─────────────────────────────────────────────────────────┐
│                     상태 관리 분리                       │
├────────────────────────┬────────────────────────────────┤
│  클라이언트 상태        │  서버 상태                     │
│  (UI, 세션 데이터)     │  (API 응답 데이터)             │
│                        │                                │
│  ✅ Zustand            │  ✅ SWR (조회)                 │
│                        │  ✅ TanStack Query (변경)      │
└────────────────────────┴────────────────────────────────┘

2. Zustand - 전역 클라이언트 상태

Zustand는 보일러플레이트가 없는 경량 전역 상태 관리 라이브러리입니다.

스토어 목록

스토어 파일 관리 상태 주요 위치
user-store.ts 로그인 사용자 정보 (이름, ID 등) shared/store/
menu-store.ts 현재 메뉴 정보, BBS 설정, 페이지 권한 shared/store/
alert-store.ts 전역 알림(Alert) 메시지 shared/store/
attachment-store.ts 첨부파일 상태 shared/store/
tab-store.ts 탭 목록 및 현재 활성 탭 store/
admin-store.ts 관리자 관련 상태 store/

2-1. 스토어 생성 패턴

Vanilla 스토어 패턴 (shared/store/ 내 스토어들):

// shared/store/menu-store.ts
import { createStore } from "zustand/vanilla";

export const createMenuStore = (initState = defaultInitState) => {
  return createStore<MenuStore>()((set) => ({
    ...initState,
    setCurrentMenuInfo: (menu) => set({ currentMenuInfo: menu }),
    // ...
  }));
};
  • zustand/vanilla를 사용하여 React에 종속되지 않는 순수 스토어를 생성
  • store-provider.tsx에서 React Context와 연결하여 컴포넌트에서 사용

React 스토어 패턴 (store/tab-store.ts):

// store/tab-store.ts
import { create } from "zustand";

const useTabStoreHook = create<TabStore>((set, get) => ({
  tabs: [],
  activeTabId: null,
  addTab: (menuItem) => { /* ... */ },
  removeTab: (tabId) => { /* ... */ },
}));

export const useTabStore = useTabStoreHook;
  • create를 사용하여 직접 React Hook 형태로 사용

2-2. 스토어 사용 패턴

// 컴포넌트에서 사용
const { setMessage: alert } = useAlertStore((state) => state);
const activeTabId = useTabStore((state) => state.activeTabId);
const userInfo = useUserStore((state) => state.userInfo);

(state) => state.xxx 셀렉터 패턴을 사용하여 필요한 상태만 구독하고, 불필요한 리렌더링을 방지합니다.


3. tab-store 설계 - 탭 UI 관리

탭 기반 내비게이션의 핵심 스토어입니다.

주요 상태

상태 타입 설명
tabs Tab[] 현재 열린 탭 목록
activeTabId string | null 현재 활성화된 탭 ID
menuList MenuItem[] | null 전체 메뉴 목록

주요 액션

액션 설명
addTab(menuItem) 탭 추가 (이미 있으면 활성화, 최대 10개 제한)
removeTab(tabId) 탭 닫기 (이전/다음 탭으로 자동 전환)
setActiveTab(tabId) 탭 활성화 전환
closeAllTabs() 모든 탭 닫기
closeOtherTabs(tabId) 현재 탭 외 모두 닫기

4. 화면 탭 포커스 감지 패턴

각 화면 컴포넌트에서 탭 전환을 감지하여 데이터를 자동 갱신하는 패턴입니다.

const activeTabId = useTabStore((state) => state.activeTabId);

useEffect(() => {
    // 이 컴포넌트의 탭이 활성화되면 데이터 새로고침
    if (activeTabId === 'StatsInputStatusInp' && swrKey) {
        mutate(swrKey);
    }
}, [activeTabId]);

동작 원리:

  1. activeTabId가 변경될 때마다 useEffect가 실행됨
  2. 현재 컴포넌트의 탭 ID와 일치하는지 확인
  3. 일치하면 SWR의 mutate()로 최신 데이터를 서버에서 다시 가져옴