본문 바로가기

TIL

TIL - 리팩토링 Zustand를 이용한 상태 관리 통합

문제 상황

운동 기록 페이지에서 상태 관리의 복잡성이 문제가 되었음. 페이지 컴포넌트는 전역 상태를 관리하고, 폼 아이템 레벨에서는 지역 상태를 관리하는 방식으로 구현되어 있었음. 이로 인해 상태 동기화와 데이터 흐름에 어려움이 발생했음.

 

상황 요약:

  • 전역 상태: 세트당 거리, 시간 또는 무게 횟수와 같은 폼 데이터를 포함하여 여러 컴포넌트에서 참조됨.
  • 지역 상태: 페이지 컴포넌트에서 관리되는 운동 기록 상태는 하위 컴포넌트로 props로 내려줌.
  • 문제점: 상태의 동기화 및 관리가 복잡해짐. 전역 상태와 지역 상태 간의 불일치가 발생함.

 

리팩토링 내용

  1. 상태 관리 구분:
    • 전역 상태: Zustand 스토어에 통합하여 여러 컴포넌트에서 공유하는 상태 관리 (record, isBookMark, cardioInputs, weightInputs, exerciseType 등).
    • 지역 상태: 주로 UI와 관련된 상태나 일시적인 사용자 입력을 처리하는 데 사용되는 상태 (searchTerm, currentExerciseId 등).
  2. 전역 상태 및 컴포넌트 리팩토링:
    • Zustand 스토어 통합: 모든 운동 관련 상태를 하나의 중앙 스토어로 통합하여 관리. 각 컴포넌트가 직접 이 스토어를 참조하여 상태를 업데이트하고 읽음.
    • 상태 업데이트 함수 개선: 상태 업데이트 로직을 개선하여 setCardioInputs, setWeightInputs, addInput, deleteInput 함수에서 record 상태도 함께 업데이트하도록 수정.
    • 컴포넌트 리팩토링: ExerciseRecordForm, CardioForm, WeightForm 등의 컴포넌트를 Zustand 스토어를 직접 사용하도록 수정하여 코드의 일관성과 유지보수성을 향상시킴.
// Zustand를 활용한 통합 상태 관리
export const useExerciseStore = create<ExerciseStore>((set) => ({
  record: exerciseInitialState,
  cardioInputs: [{ minutes: null, distance: null }],
  weightInputs: [{ weight: null, reps: null }],
  exerciseType: 'weight',
  
  setRecord: (update) =>
    set((state) => {
      const newRecord = { ...state.record, ...update };
      // 조건에 따라 cardioInputs 또는 weightInputs 업데이트
      if ('record' in update) {
        if (newRecord.exerciseType === 'cardio') {
          newState.cardioInputs = update.record;
        } else {
          newState.weightInputs = update.record;
        }
      }
      return newState;
    }),

  addInput: () =>
    set((state) => {
      if (state.exerciseType === 'cardio') {
        return { cardioInputs: [...state.cardioInputs, { minutes: null, distance: null }] };
      } else {
        return { weightInputs: [...state.weightInputs, { weight: null, reps: null }] };
      }
    }),

  deleteInput: (index) =>
    set((state) => {
      const inputs = state.exerciseType === 'cardio' ? state.cardioInputs : state.weightInputs;
      if (inputs.length <= 1) {
        alert('최소 한 개의 세트는 필요합니다.');
        return state;
      }
      return {
        cardioInputs: state.cardioInputs.filter((_, i) => i !== index),
        weightInputs: state.weightInputs.filter((_, i) => i !== index),
      };
    }),
}));

결과:

  • 데이터 일관성: 페이지 레벨의 상태와 폼 아이템 레벨의 상태가 항상 동기화됨.
  • 단순화된 데이터 흐름: 모든 컴포넌트가 동일한 중앙 스토어를 참조하여 데이터 흐름이 명확해짐.
  • 유지보수성 개선: 중앙 집중식 상태 관리로 코드의 예측 가능성과 디버깅 용이성이 향상됨.

 

리팩토링을 통해 전역 상태와 지역 상태의 역할을 명확히 구분하고, 상태 관리의 복잡성을 줄이면서 코드의 가독성과 유지보수성을 높일 수 있었습니다