
InMyDay
문제 배경
체험 수정 페이지(ExperienceEditPage)에서
이미 예약이 존재하는 일정을 삭제한 상태로 수정 요청을 보내면,
백엔드에서 “예약된 일정은 삭제 불가” 에러를 반환했다.
에러 자체는 정상적으로 처리되었지만,
문제는 그 이후 UI 상태였다.
- 서버에서는 삭제가 실패했는데
- 프론트엔드 UI에서는 일정이 이미 삭제된 것처럼 유지됨
결과적으로 사용자는
“삭제가 된 건지, 안 된 건지”
를 판단할 수 없는 상태에 놓이게 됐다.
즉, 에러는 발생했지만 UI가 서버 상태로 복구되지 않는 문제였다.
🔍 원인 분석
이 문제는 단일 원인이 아니라
서버 / 캐시 / 로컬 상태 / UI 컴포넌트 상태가 동시에 어긋난 구조에서 발생했다.
구분원인
| 1 | Mutation 실패 후 onError에서 UI 복구 로직이 없었음 |
| 2 | React Query 캐시(activityDetail)가 최신 서버 상태로 갱신되지 않음 |
| 3 | form.schedules는 삭제된 상태를 그대로 유지 |
| 4 | DateSection 내부 useState가 stale 상태를 유지 |
| 5 | 임시 해결로 window.location.reload()를 사용하던 상태 |
정리하면 이거다.
서버는 “삭제 안 됨”인데
프론트는 “삭제됨”이라고 믿고 계속 화면을 그리고 있었다.
🛠️ 해결 전략
이 문제를 로컬 상태만 되돌리는 방식으로 해결하지 않았다.
항상서버를 단일 진실(Single Source of Truth)로 두는 구조로 수정했다.
핵심 전략은 3단계다.
1️⃣ React Query 캐시 무효화 (서버 상태 재동기화)
Mutation 실패 시,
기존 캐시를 신뢰하지 않고 서버 데이터를 다시 가져오도록 했다.
queryClient.invalidateQueries({ queryKey: ["activityDetail", id] });
- 실패한 요청 이후에도 캐시는 그대로 남아 있었기 때문에
- 반드시 서버 기준 최신 상태를 다시 패칭하도록 강제했다
👉 서버 상태 최신화 담당
2️⃣ 로컬 form 상태를 서버 데이터로 복구
React Query의 data는 최신화되지만,
form은 여전히 삭제된 상태를 들고 있었다.
그래서 invalidate 이후 서버 데이터를 기준으로
form.schedules를 다시 덮어썼다.
setForm((prev) => ({
...prev!,
schedules: [...(data.schedules as Slot[])],
}));
👉 로컬 상태(form) 복구 담당
3️⃣ DateSection 강제 리마운트 (UI 내부 상태 초기화)
DateSection은 내부에 useState를 가지고 있어
props만 바뀌어도 이전 상태를 유지하고 있었다.
이를 해결하기 위해 key를 변경해
컴포넌트를 완전히 새로 마운트하도록 했다.
setDateSectionKey((prev) => prev + 1);
- React에서 key가 바뀌면 컴포넌트는 완전히 재생성된다
- 내부 상태(useState, 캐시)를 전부 초기화할 수 있다
👉 UI 컴포넌트 내부 상태 리셋 담당
🧠 왜 세 개를 다 써야 했나?
이 세 가지는 역할 레이어가 다르다.
처리담당 레이어빠지면 생기는 문제
| invalidateQueries | 서버 캐시 (React Query) | 서버는 복구됐는데 캐시는 옛날 데이터 |
| setForm | 로컬 상태 | 캐시는 최신인데 화면은 삭제된 상태 |
| key 변경 | UI 컴포넌트 | props는 바뀌었는데 화면이 그대로 |
그래서 이 순서가 필요했다.
invalidateQueries() // 서버 기준 최신화
↓
setForm() // 로컬 상태 복구
↓
setDateSectionKey() // UI 내부 상태 초기화
하나라도 빠지면 서버–UI 불일치가 다시 발생한다.
🚫 window.location.reload()를 제거한 이유
기존에는 전체 새로고침으로 문제를 우회하고 있었다.
하지만 이 방식은:
- 모든 React Query 캐시 초기화
- 폼 입력값 전부 유실
- UX 단절
이라는 문제가 있었다.
현재 구조는:
- 필요한 데이터만 서버에서 재패칭
- 필요한 컴포넌트만 리마운트
👉 페이지 전체 리로드 없이, 동일한 효과를 내는 구조로 개선했다.
✅ 결과
- 삭제 실패 시 UI가 즉시 서버 상태로 복구됨
- 새로고침 없이도 수정 화면이 안정적으로 유지됨
- 서버–UI 데이터 불일치로 인한 사용자 혼란 제거
- 실패 가능성이 높은 도메인에서 보수적인 동기화 전략 확립
📌 정리
이 문제는 단순한 에러 핸들링 문제가 아니라,
“서버 / 캐시 / 로컬 상태 / UI 내부 상태를
어떤 기준으로 동기화할 것인가”
에 대한 문제였다.
이번 개선을 통해
서버를 기준으로 UI를 복구하는 흐름을 명확히 만들었고,
실패 상황에서도 예측 가능한 수정 화면을 제공할 수 있게 됐다.