graph TD
subgraph "Before - 복잡한 상태 관리"
A[QuizZonePage] --> B[useQuizZoneManager]
B --> C[상태 관리]
B --> D[WebSocket 통신]
B --> E[타이머 관리]
C --> F[퀴즈 상태]
C --> G[타이머 상태]
C --> H[사용자 상태]
end
subgraph "After - 관심사 분리"
I[QuizZonePage] --> J[useQuizZone]
I --> K[useTimer]
J --> L[useWebSocket]
J --> M[상태 관리 Reducer]
L --> N[WebSocket 이벤트]
K --> O[타이머 로직]
end
이전 구조에서는 모든 로직이 useQuizZoneManager에 집중되어 있어 코드의 복잡도가 높고 유지보수가 어려웠습니다. 리팩토링을 통해 각 기능을 독립적인 훅으로 분리하여 관심사를 명확히 구분했습니다.
sequenceDiagram
participant Client
participant useQuizZone
participant useWebSocket
participant Server
Client->>useQuizZone: initQuizZoneData()
useQuizZone->>useWebSocket: 연결 수립
useWebSocket->>Server: WebSocket 연결
Server-->>useWebSocket: 초기 데이터
useWebSocket-->>useQuizZone: dispatch(init)
useQuizZone-->>Client: 상태 업데이트
단방향 데이터 흐름을 명확히 하여 상태 변화의 예측 가능성을 높였습니다. WebSocket 이벤트 처리가 중앙화되어 데이터 일관성이 향상되었습니다.
이러한 복잡도 감소는 코드의 이해도와 유지보수성을 크게 향상시켰습니다.
책임 분리
// 이전: 모든 로직이 한 곳에 집중
const useQuizZoneManager = (config: QuizStageConfig) => {
const [quizZone, setQuizZone] = useState<QuizZone>('LOBBY');
const [solveStage, setSolveStage] = useState<SolveStage>('WAITING');
// ... 수많은 상태와 로직
};
// 이후: 명확한 책임 분리
const useQuizZone = () => {
const [state, dispatch] = useReducer(quizZoneReducer, initialState);
const { sendMessage } = useWebSocket(url, messageHandler);
// ... 핵심 퀴즈 로직
};
const useTimer = ({ initialTime, onComplete }: TimerConfig) => {
// ... 타이머 관련 로직
};
// 명확한 액션 타입 정의
type QuizZoneAction =
| { type: 'init'; payload: QuizZone }
| { type: 'nextQuiz'; payload: CurrentQuiz }
| { type: 'playQuiz'; payload: undefined }
| { type: 'submit'; payload: undefined };
// 중앙화된 상태 관리
const quizZoneReducer = (state: QuizZone, action: QuizZoneAction) => {
switch (action.type) {
case 'init':
return {
...state,
...action.payload,
stage: 'LOBBY'
};
// ... 기타 케이스
}
};