# 트러블슈팅 가이드 ## 📋 목차 1. [일반적인 문제](#일반적인-문제) 2. [큐 시스템 문제](#큐-시스템-문제) 3. [API 호출 문제](#api-호출-문제) 4. [성능 문제](#성능-문제) 5. [디버깅 팁](#디버깅-팁) --- ## 일반적인 문제 ### 문제 1: dispatch 순서가 여전히 보장되지 않음 #### 증상 ```javascript dispatch(action1()); dispatch(action2()); dispatch(action3()); // 실행 순서: action2 → action3 → action1 ``` #### 가능한 원인 1. **일반 dispatch와 큐 dispatch 혼용** ```javascript // ❌ 잘못된 사용 dispatch(pushPanel({ name: 'PANEL_1' })); // 일반 dispatch(pushPanelQueued({ name: 'PANEL_2' })); // 큐 ``` 2. **async/await 없이 비동기 처리** ```javascript // ❌ 잘못된 사용 fetchData(); // Promise를 기다리지 않음 dispatch(action()); ``` 3. **헬퍼 함수를 사용하지 않음** ```javascript // ❌ 잘못된 사용 dispatch(asyncAction1()); dispatch(asyncAction2()); // asyncAction1이 완료되기 전에 실행 ``` #### 해결 방법 **방법 1: 큐 시스템 사용** (패널 액션인 경우) ```javascript // ✅ 올바른 사용 dispatch(enqueueMultiplePanelActions([ pushPanelQueued({ name: 'PANEL_1' }), pushPanelQueued({ name: 'PANEL_2' }), pushPanelQueued({ name: 'PANEL_3' }) ])); ``` **방법 2: createSequentialDispatch 사용** ```javascript // ✅ 올바른 사용 dispatch(createSequentialDispatch([ action1(), action2(), action3() ])); ``` **방법 3: async/await 사용** (Chrome 68+) ```javascript // ✅ 올바른 사용 export const myAction = () => async (dispatch, getState) => { await dispatch(action1()); await dispatch(action2()); await dispatch(action3()); }; ``` --- ### 문제 2: "Cannot find module" 에러 #### 증상 ``` Error: Cannot find module '../utils/dispatchHelper' Error: Cannot find module '../middleware/panelQueueMiddleware' ``` #### 원인 - 파일이 존재하지 않음 - import 경로가 잘못됨 - 빌드가 필요함 #### 해결 방법 **Step 1: 파일 존재 확인** ```bash # 프로젝트 루트에서 실행 ls -la com.twin.app.shoptime/src/utils/dispatchHelper.js ls -la com.twin.app.shoptime/src/middleware/panelQueueMiddleware.js ls -la com.twin.app.shoptime/src/utils/asyncActionUtils.js ``` **Step 2: 최신 코드 pull** ```bash git fetch origin git pull origin ``` **Step 3: node_modules 재설치** ```bash cd com.twin.app.shoptime rm -rf node_modules package-lock.json npm install ``` **Step 4: 빌드 재실행** ```bash npm run build # 또는 npm start ``` --- ### 문제 3: 타입 에러 (types is not defined) #### 증상 ``` ReferenceError: types is not defined TypeError: Cannot read property 'ENQUEUE_PANEL_ACTION' of undefined ``` #### 원인 actionTypes.js에 필요한 타입이 정의되지 않음 #### 해결 방법 **Step 1: actionTypes.js 확인** ```javascript // src/actions/actionTypes.js export const types = { // ... 기존 타입들 ... // 큐 관련 타입들 (필수!) ENQUEUE_PANEL_ACTION: 'ENQUEUE_PANEL_ACTION', PROCESS_PANEL_QUEUE: 'PROCESS_PANEL_QUEUE', CLEAR_PANEL_QUEUE: 'CLEAR_PANEL_QUEUE', SET_QUEUE_PROCESSING: 'SET_QUEUE_PROCESSING', // 비동기 액션 타입들 (필수!) ENQUEUE_ASYNC_PANEL_ACTION: 'ENQUEUE_ASYNC_PANEL_ACTION', COMPLETE_ASYNC_PANEL_ACTION: 'COMPLETE_ASYNC_PANEL_ACTION', FAIL_ASYNC_PANEL_ACTION: 'FAIL_ASYNC_PANEL_ACTION', }; ``` **Step 2: import 확인** ```javascript import { types } from '../actions/actionTypes'; ``` --- ## 큐 시스템 문제 ### 문제 4: 큐가 처리되지 않음 #### 증상 ```javascript dispatch(pushPanelQueued({ name: panel_names.SEARCH_PANEL })); // 아무 일도 일어나지 않음 // 콘솔 로그도 없음 ``` #### 원인 **panelQueueMiddleware가 등록되지 않음** (가장 흔한 문제!) #### 해결 방법 **Step 1: store.js 확인** ```javascript // src/store/store.js import panelQueueMiddleware from '../middleware/panelQueueMiddleware'; export const store = createStore( rootReducer, applyMiddleware( thunk, panelHistoryMiddleware, autoCloseMiddleware, panelQueueMiddleware // ← 이것이 있는지 확인! ) ); ``` **Step 2: import 경로 확인** ```javascript // ✅ 올바른 import import panelQueueMiddleware from '../middleware/panelQueueMiddleware'; // ❌ 잘못된 import import { panelQueueMiddleware } from '../middleware/panelQueueMiddleware'; // default export이므로 중괄호 없이 import해야 함 ``` **Step 3: 앱 재시작** ```bash # 개발 서버 재시작 npm start ``` **Step 4: 브라우저 캐시 삭제** - Chrome: Ctrl+Shift+R (Windows) 또는 Cmd+Shift+R (Mac) --- ### 문제 5: 큐가 무한 루프에 빠짐 #### 증상 ``` [panelQueueMiddleware] 🚀 ACTION_ENQUEUED [panelQueueMiddleware] ⚡ STARTING_QUEUE_PROCESS [panelReducer] 🟡 PROCESS_PANEL_QUEUE [panelReducer] 🟡 PROCESS_PANEL_QUEUE [panelReducer] 🟡 PROCESS_PANEL_QUEUE ... (무한 반복) ``` #### 원인 1. 큐 처리 중에 다시 큐에 액션 추가 2. `isProcessingQueue` 플래그가 제대로 설정되지 않음 #### 해결 방법 **방법 1: 큐 액션 내부에서 일반 dispatch 사용** ```javascript // ❌ 잘못된 사용 (무한 루프 발생) export const myAction = () => (dispatch) => { dispatch(pushPanelQueued({ name: 'PANEL_1' })); dispatch(pushPanelQueued({ name: 'PANEL_2' })); // 큐 처리 중 큐 추가 }; // ✅ 올바른 사용 export const myAction = () => (dispatch) => { dispatch(enqueueMultiplePanelActions([ pushPanelQueued({ name: 'PANEL_1' }), pushPanelQueued({ name: 'PANEL_2' }) ])); }; ``` **방법 2: 리듀서 로직 확인** ```javascript // panelReducer.js에서 확인 case types.PROCESS_PANEL_QUEUE: { // 이미 처리 중이면 무시 if (state.isProcessingQueue || state.panelActionQueue.length === 0) { return state; // ← 이 로직이 있는지 확인 } // ... } ``` --- ### 문제 6: 큐 통계가 업데이트되지 않음 #### 증상 ```javascript store.getState().panels.queueStats // { totalProcessed: 0, failedCount: 0, averageProcessingTime: 0 } // 항상 0으로 유지됨 ``` #### 원인 큐 처리가 정상적으로 완료되지 않음 #### 해결 방법 **Step 1: 콘솔 로그 확인** ``` [panelReducer] ✅ QUEUE_ITEM_PROCESSED ← 이 로그가 보이는지 확인 ``` **Step 2: 에러 발생 확인** ```javascript store.getState().panels.queueError // null이어야 정상 ``` **Step 3: 큐 처리 완료 여부 확인** ```javascript store.getState().panels.isProcessingQueue // false여야 정상 (처리 완료) ``` --- ## API 호출 문제 ### 문제 7: API 성공인데 onFail이 호출됨 #### 증상 ```javascript // API 호출 // HTTP 200, retCode: 0 // 그런데 onFail이 호출됨 ``` #### 원인 프로젝트 성공 기준을 이해하지 못함 #### 프로젝트 성공 기준 **HTTP 200-299 + retCode 0/'0' 둘 다 만족해야 성공!** ```javascript // ✅ 성공 케이스 { status: 200, data: { retCode: 0, data: {...} } } { status: 200, data: { retCode: '0', data: {...} } } // ❌ 실패 케이스 { status: 200, data: { retCode: 1, message: '에러' } } // retCode가 0이 아님 { status: 500, data: { retCode: 0, data: {...} } } // HTTP 에러 ``` #### 해결 방법 **방법 1: isApiSuccess 사용** ```javascript import { isApiSuccess } from '../utils/asyncActionUtils'; const response = { status: 200 }; const responseData = { retCode: 1, message: '에러' }; if (isApiSuccess(response, responseData)) { // 성공 처리 } else { // 실패 처리 (retCode가 1이므로 실패!) } ``` **방법 2: asyncActionUtils 사용** ```javascript import { tAxiosToPromise } from '../utils/asyncActionUtils'; const result = await tAxiosToPromise(...); if (result.success) { // HTTP 200-299 + retCode 0/'0' console.log(result.data); } else { // 실패 console.error(result.error); } ``` --- ### 문제 8: API 타임아웃이 작동하지 않음 #### 증상 ```javascript dispatch(enqueueAsyncPanelAction({ asyncAction: (d, gs, onS, onF) => { /* 느린 API */ }, timeout: 5000 // 5초 })); // 10초가 지나도 타임아웃되지 않음 ``` #### 원인 1. `withTimeout`이 적용되지 않음 2. 타임아웃 값이 잘못 설정됨 #### 해결 방법 **방법 1: enqueueAsyncPanelAction 사용 시** ```javascript // ✅ timeout 옵션 사용 dispatch(enqueueAsyncPanelAction({ asyncAction: (dispatch, getState, onSuccess, onFail) => { TAxios(dispatch, getState, 'get', URL, {}, {}, onSuccess, onFail); }, timeout: 5000, // 5초 (ms 단위) onFail: (error) => { if (error.code === 'TIMEOUT') { console.error('타임아웃 발생!'); } } })); ``` **방법 2: withTimeout 직접 사용** ```javascript import { withTimeout, fetchApi } from '../utils/asyncActionUtils'; const result = await withTimeout( fetchApi('/api/slow-endpoint'), 5000, // 5초 '요청 시간이 초과되었습니다' ); if (result.error?.code === 'TIMEOUT') { console.error('타임아웃!'); } ``` --- ## 성능 문제 ### 문제 9: 큐 처리가 너무 느림 #### 증상 ```javascript // 100개의 패널 액션을 큐에 추가 // 처리하는데 10초 이상 소요 ``` #### 원인 1. 각 액션이 복잡한 로직 수행 2. 동기적으로 처리되어 병목 발생 #### 해결 방법 **방법 1: 불필요한 액션 제거** ```javascript // ❌ 잘못된 사용 for (let i = 0; i < 100; i++) { dispatch(pushPanelQueued({ name: `PANEL_${i}` })); } // ✅ 올바른 사용 - 필요한 것만 dispatch(pushPanelQueued({ name: 'MAIN_PANEL' })); ``` **방법 2: 배치 처리** ```javascript // 한 번에 여러 액션 추가 dispatch(enqueueMultiplePanelActions( panels.map(panel => pushPanelQueued(panel)) )); ``` **방법 3: 병렬 처리가 필요하면 큐 사용 안함** ```javascript // 순서가 중요하지 않은 경우 dispatch(createParallelDispatch([ fetchData1(), fetchData2(), fetchData3() ])); ``` --- ### 문제 10: 메모리 누수 #### 증상 ```javascript // 오랜 시간 앱 사용 후 store.getState().panels.completedAsyncActions.length // → 10000개 이상 ``` #### 원인 완료된 비동기 액션 ID가 계속 누적됨 #### 해결 방법 **방법 1: 주기적으로 클리어** ```javascript // 일정 시간마다 완료된 액션 정리 setInterval(() => { const state = store.getState().panels; if (state.completedAsyncActions.length > 1000) { // 클리어 액션 dispatch dispatch({ type: types.CLEAR_COMPLETED_ASYNC_ACTIONS }); } }, 60000); // 1분마다 ``` **방법 2: 리듀서에 최대 개수 제한 추가** ```javascript // panelReducer.js case types.COMPLETE_ASYNC_PANEL_ACTION: { const newCompleted = [...state.completedAsyncActions, action.payload.actionId]; // 최근 100개만 유지 const trimmed = newCompleted.slice(-100); return { ...state, completedAsyncActions: trimmed }; } ``` --- ## 디버깅 팁 ### Tip 1: 콘솔 로그 활용 모든 헬퍼 함수와 미들웨어는 상세한 로그를 출력합니다: ```javascript // 큐 관련 로그 [panelQueueMiddleware] 🚀 ACTION_ENQUEUED [panelQueueMiddleware] ⚡ STARTING_QUEUE_PROCESS [panelReducer] 🟡 PROCESS_PANEL_QUEUE [panelReducer] 🟡 PROCESSING_QUEUE_ITEM [panelReducer] ✅ QUEUE_ITEM_PROCESSED // 비동기 액션 로그 [queuedPanelActions] 🔄 ENQUEUE_ASYNC_PANEL_ACTION [queuedPanelActions] ⚡ EXECUTING_ASYNC_ACTION [queuedPanelActions] ✅ ASYNC_ACTION_SUCCESS // asyncActionUtils 로그 [asyncActionUtils] 🌐 FETCH_API_START [asyncActionUtils] 📊 API_RESPONSE [asyncActionUtils] ✅ TAXIOS_SUCCESS ``` ### Tip 2: Redux DevTools 사용 1. Chrome 확장 프로그램 설치: Redux DevTools 2. 개발자 도구 → Redux 탭 3. 액션 히스토리 확인 4. State diff 확인 ### Tip 3: 브레이크포인트 설정 ```javascript // 디버깅용 브레이크포인트 export const myAction = () => (dispatch, getState) => { debugger; // ← 여기서 멈춤 const state = getState(); console.log('Current state:', state); dispatch(action1()); debugger; // ← 여기서 다시 멈춤 }; ``` ### Tip 4: State 스냅샷 ```javascript // 콘솔에서 실행 const snapshot = JSON.parse(JSON.stringify(store.getState())); console.log(snapshot); // 특정 부분만 const panelsSnapshot = JSON.parse(JSON.stringify(store.getState().panels)); console.log(panelsSnapshot); ``` ### Tip 5: 큐 상태 모니터링 ```javascript // 콘솔에서 실행 window.monitorQueue = setInterval(() => { const state = store.getState().panels; console.log('Queue status:', { queueLength: state.panelActionQueue.length, isProcessing: state.isProcessingQueue, stats: state.queueStats }); }, 1000); // 중지 clearInterval(window.monitorQueue); ``` --- ## 도움이 필요하신가요? ### 체크리스트 문제 해결 전에 다음을 확인하세요: - [ ] panelQueueMiddleware가 store.js에 등록되어 있는가? - [ ] 필요한 파일들이 모두 존재하는가? - [ ] actionTypes.js에 필요한 타입들이 정의되어 있는가? - [ ] 콘솔 로그를 확인했는가? - [ ] Redux DevTools로 액션 흐름을 확인했는가? - [ ] 앱을 재시작했는가? - [ ] 브라우저 캐시를 삭제했는가? ### 추가 리소스 - [README.md](./README.md) - 전체 개요 - [06-setup-guide.md](./06-setup-guide.md) - 설정 가이드 - [05-usage-patterns.md](./05-usage-patterns.md) - 사용 패턴 - [07-changelog.md](./07-changelog.md) - 변경 이력 --- **작성일**: 2025-11-10 **최종 수정일**: 2025-11-10