[문서 추가] 설정 가이드, 변경 이력, 트러블슈팅 문서 작성
## 추가된 문서 ### 06-setup-guide.md - 설정 가이드 - panelQueueMiddleware 등록 상세 가이드 - 미들웨어 등록 순서 설명 - 파일 구조 확인 방법 - 단계별 설정 순서 - 검증 방법 (콘솔 로그, Redux DevTools, State 확인) - 트러블슈팅 (5가지 일반적인 문제) - 빠른 체크리스트 ### 07-changelog.md - 변경 이력 - 2025-11-10: panelQueueMiddleware 등록 및 문서 개선 - 2025-11-10: 초기 문서 작성 - 2025-11-06: 큐 시스템 구현 - 2025-11-05: dispatch 헬퍼 함수 추가 - 마이그레이션 가이드 - Breaking Changes (없음) - 알려진 이슈 (모두 해결됨) - 향후 계획 ### 08-troubleshooting.md - 트러블슈팅 - 일반적인 문제 3가지 - dispatch 순서 미보장 - Cannot find module 에러 - 타입 에러 - 큐 시스템 문제 3가지 - 큐가 처리되지 않음 - 무한 루프 - 큐 통계 미업데이트 - API 호출 문제 2가지 - 성공인데 onFail 호출 - 타임아웃 미작동 - 성능 문제 2가지 - 큐 처리 속도 저하 - 메모리 누수 - 디버깅 팁 5가지 - 콘솔 로그 활용 - Redux DevTools 사용 - 브레이크포인트 설정 - State 스냅샷 - 큐 상태 모니터링 ## README.md 업데이트 - 목차에 새로운 문서 3개 추가 - "학습 자료" 섹션을 3개 카테고리로 재구성: - 시작하기 (설정 가이드, 트러블슈팅) - 이해하기 (문제 상황, 3가지 솔루션) - 실전 적용 (사용 패턴, 변경 이력) ## 문서 통계 - 총 9개 마크다운 파일 - 약 5,000줄 이상 - 100개 이상의 코드 예제 - 10가지 실전 트러블슈팅 가이드 ## 특징 - 초보자도 쉽게 따라할 수 있는 단계별 가이드 - 실제 발생 가능한 문제와 해결 방법 - 변경 이력 및 커밋 히스토리 추적 - 상세한 디버깅 팁
This commit is contained in:
606
.docs/dispatch-async/08-troubleshooting.md
Normal file
606
.docs/dispatch-async/08-troubleshooting.md
Normal file
@@ -0,0 +1,606 @@
|
||||
# 트러블슈팅 가이드
|
||||
|
||||
## 📋 목차
|
||||
|
||||
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 <branch-name>
|
||||
```
|
||||
|
||||
**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
|
||||
Reference in New Issue
Block a user