Files
shoptime/com.twin.app.shoptime/.docs/dispatch-async/01-problem.md
optrader fd5a171a28 restore: .docs 폴더 복원 및 .gitignore 수정
- claude/ 브랜치에서 누락된 .docs 폴더 복원 완료
- dispatch-async 관련 문서 9개 파일 복원
  * 01-problem.md, 02-solution-dispatch-helper.md
  * 03-solution-async-utils.md, 04-solution-queue-system.md
  * 05-usage-patterns.md, 06-setup-guide.md
  * 07-changelog.md, 08-troubleshooting.md, README.md
- MediaPlayer.v2 관련 문서 4개 파일 복원
  * MediaPlayer-v2-README.md, MediaPlayer-v2-Required-Changes.md
  * MediaPlayer-v2-Risk-Analysis.md, PR-MediaPlayer-v2.md
- 기타 분석 문서 2개 파일 복원
  * modal-transition-analysis.md, video-player-analysis-and-optimization-plan.md
- .gitignore에서 .docs 항목 제거로 문서 추적 가능하도록 수정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: GLM 4.6 <noreply@z.ai>
2025-11-11 10:00:59 +09:00

211 lines
5.5 KiB
Markdown

# 문제 상황: Dispatch 비동기 순서 미보장
## 🔴 핵심 문제
Redux-thunk는 비동기 액션을 지원하지만, **여러 개의 dispatch를 순차적으로 호출할 때 실행 순서가 보장되지 않습니다.**
## 📝 기존 코드의 문제점
### 예제 1: homeActions.js
**파일**: `src/actions/homeActions.js`
```javascript
export const getHomeTerms = (props) => (dispatch, getState) => {
const onSuccess = (response) => {
if (response.data.retCode === 0) {
// 첫 번째 dispatch
dispatch({
type: types.GET_HOME_TERMS,
payload: response.data,
});
// 두 번째 dispatch
dispatch({
type: types.SET_TERMS_ID_MAP,
payload: termsIdMap,
});
// ⚠️ 문제: setTimeout으로 순서 보장 시도
setTimeout(() => {
dispatch(getTermsAgreeYn());
}, 0);
}
};
TAxios(dispatch, getState, "get", URLS.GET_HOME_TERMS, ..., onSuccess, onFail);
};
```
**문제점**:
1. `setTimeout(fn, 0)`은 임시방편일 뿐, 명확한 해결책이 아님
2. 코드 가독성이 떨어짐
3. 타이밍 이슈로 인한 버그 가능성
4. 유지보수가 어려움
### 예제 2: cartActions.js
**파일**: `src/actions/cartActions.js`
```javascript
export const addToCart = (props) => (dispatch, getState) => {
const onSuccess = (response) => {
// 첫 번째 dispatch: 카트에 추가
dispatch({
type: types.ADD_TO_CART,
payload: response.data.data,
});
// 두 번째 dispatch: 카트 정보 재조회
// ⚠️ 문제: 순서가 보장되지 않음
dispatch(getMyInfoCartSearch({ mbrNo }));
};
TAxios(dispatch, getState, "post", URLS.ADD_TO_CART, ..., onSuccess, onFail);
};
```
**문제점**:
1. `getMyInfoCartSearch``ADD_TO_CART`보다 먼저 실행될 수 있음
2. 카트 정보가 업데이트되기 전에 재조회가 실행될 수 있음
3. 순서가 보장되지 않아 UI에 잘못된 데이터가 표시될 수 있음
## 🤔 왜 순서가 보장되지 않을까?
### Redux-thunk의 동작 방식
```javascript
// Redux-thunk는 이렇게 동작합니다
function dispatch(action) {
if (typeof action === 'function') {
// thunk action인 경우
return action(dispatch, getState);
} else {
// plain action인 경우
return next(action);
}
}
```
### 문제 시나리오
```javascript
// 이렇게 작성하면
dispatch({ type: 'ACTION_1' }); // Plain action - 즉시 실행
dispatch(asyncAction()); // Thunk - 비동기 실행
dispatch({ type: 'ACTION_2' }); // Plain action - 즉시 실행
// 실제 실행 순서는
// 1. ACTION_1 (동기)
// 2. ACTION_2 (동기)
// 3. asyncAction의 내부 dispatch들 (비동기)
// 즉, asyncAction이 완료되기 전에 ACTION_2가 실행됩니다!
```
## 🎯 해결해야 할 과제
1. **순서 보장**: 여러 dispatch가 의도한 순서대로 실행되도록
2. **에러 처리**: 중간에 에러가 발생해도 체인이 끊기지 않도록
3. **가독성**: 코드가 직관적이고 유지보수하기 쉽도록
4. **재사용성**: 여러 곳에서 쉽게 사용할 수 있도록
5. **호환성**: 기존 코드와 호환되도록
## 📊 실제 발생 가능한 버그
### 시나리오 1: 카트 추가 후 조회
```javascript
// 의도한 순서
1. ADD_TO_CART dispatch
2. 상태 업데이트
3. getMyInfoCartSearch dispatch
4. 최신 카트 정보 조회
// 실제 실행 순서 (문제)
1. ADD_TO_CART dispatch
2. getMyInfoCartSearch dispatch (너무 빨리 실행!)
3. 이전 카트 정보 조회 (아직 상태 업데이트 안됨)
4. 상태 업데이트
결과: UI에 이전 데이터가 표시됨
```
### 시나리오 2: 패널 열고 닫기
```javascript
// 의도한 순서
1. PUSH_PANEL (검색 패널 열기)
2. UPDATE_PANEL (검색 결과 표시)
3. POP_PANEL (이전 패널 닫기)
// 실제 실행 순서 (문제)
1. PUSH_PANEL
2. POP_PANEL (너무 빨리 실행!)
3. UPDATE_PANEL (이미 닫힌 패널을 업데이트)
결과: 패널이 제대로 표시되지 않음
```
## 🔧 기존 해결 방법과 한계
### 방법 1: setTimeout 사용
```javascript
dispatch(action1());
setTimeout(() => {
dispatch(action2());
}, 0);
```
**한계**:
- 명확한 순서 보장 없음
- 타이밍에 의존적
- 코드 가독성 저하
- 유지보수 어려움
### 방법 2: 콜백 중첩
```javascript
const action1 = (callback) => (dispatch, getState) => {
dispatch({ type: 'ACTION_1' });
if (callback) callback();
};
dispatch(action1(() => {
dispatch(action2(() => {
dispatch(action3());
}));
}));
```
**한계**:
- 콜백 지옥
- 에러 처리 복잡
- 코드 가독성 최악
### 방법 3: async/await
```javascript
export const complexAction = () => async (dispatch, getState) => {
await dispatch(action1());
await dispatch(action2());
await dispatch(action3());
};
```
**한계**:
- Chrome 68 호환성 문제 (프로젝트 요구사항)
- 모든 action이 Promise를 반환해야 함
- 기존 코드 대량 수정 필요
## 🎯 다음 단계
이제 이러한 문제들을 해결하기 위한 3가지 솔루션을 살펴보겠습니다:
1. [dispatchHelper.js](./02-solution-dispatch-helper.md) - Promise 체인 기반 헬퍼 함수
2. [asyncActionUtils.js](./03-solution-async-utils.md) - Promise 기반 비동기 처리 유틸리티
3. [큐 기반 패널 액션 시스템](./04-solution-queue-system.md) - 미들웨어 기반 큐 시스템
---
**다음**: [해결 방법 1: dispatchHelper.js →](./02-solution-dispatch-helper.md)