docs: 프론트엔드 메시지 중복 표시 문제 해결 문서 업데이트 - 최종 수정 사항 반영

This commit is contained in:
Claude-51124 2025-11-23 10:02:44 +09:00
parent 725147f58b
commit 56024d4496

View File

@ -62,14 +62,12 @@
- `user` 객체는 참조가 변경될 수 있어 불필요한 재실행 발생
- 히스토리는 "로그인 성공 후 1번만" 불러오면 충분한데, `user`를 의존성에 넣어서 "유저 객체 변경 시마다" 다시 불러오는 것이 과함
**2. `setMessages(sortedMessages)``handleSend``setMessages(prev => [...prev, ...])` 비동기 경쟁** (핵심 원인):
- `loadInitialMessages``setMessages(sortedMessages)`는 전체 덮어쓰기
- `handleSend``setMessages(prev => [...prev, robeingMessage])`는 추가
- 두 비동기 작업이 동시에 실행되면:
- 히스토리 로드가 먼저 끝나면 `setMessages(sortedMessages)`로 덮어쓰기
- 이후 `handleSend``setMessages(prev => [...prev, robeingMessage])`가 실행되면
- 히스토리에 이미 포함된 메시지와 동일한 내용이 한 번 더 추가됨
- 결과: 같은 텍스트, 다른 ID → 두 번 표시됨
**2. `loadInitialMessages`의 두 경로가 모두 `setMessages` 호출** (핵심 원인):
- 경로 1: `getMessages()`로 히스토리 로드 → 병합 로직 실행 후 `return`
- 경로 2: `getMessages()`가 빈 배열 반환 → `getUserHistory()`로 기본 메시지 생성 → `setMessages(initialMessages)` 실행 (덮어쓰기)
- 문제: `getMessages()`가 빈 배열을 반환하면 `return`이 실행되지 않아 기본 메시지가 추가됨
- `setMessages(initialMessages)`는 덮어쓰기 방식이라, 이미 추가된 메시지와 병합되지 않음
- 결과: `handleSend`에서 추가한 메시지와 기본 메시지가 중복 표시됨
---
@ -93,47 +91,66 @@
- `user` 변경 시 `loadInitialMessages`가 재실행되지 않음
- 히스토리는 로그인 성공 시(`isAuthenticated` 변경) 1번만 로드
### 적용 2: 히스토리 메시지 병합 및 중복 제거
### 적용 2: 히스토리 로드 실패 시 기본 메시지 추가 방지
**위치**: `frontend-customer/src/components/chat-interface.tsx:272`
**위치**: `frontend-customer/src/components/chat-interface.tsx:250-306`
**수정 내용**:
- `getMessages()`가 빈 배열을 반환해도, 이미 메시지가 있으면 기본 메시지를 추가하지 않도록 수정
- `historyLoadedSuccessfully` 플래그 추가하여 히스토리 로드 성공 여부 추적
- 히스토리 로드 실패 시에도 이미 메시지가 있으면 `return`하여 기본 메시지 추가 방지
**효과**:
- `getMessages()`가 빈 배열을 반환해도 불필요한 기본 메시지 추가 방지
- 이미 메시지가 있는 상태에서 `loadInitialMessages`가 재실행되어도 중복 방지
### 적용 3: 기본 메시지 병합 방식으로 변경
**위치**: `frontend-customer/src/components/chat-interface.tsx:394-422`
**수정 전**:
```typescript
setMessages(sortedMessages); // 전체 덮어쓰기
setMessages(initialMessages); // 덮어쓰기
```
**수정 후**:
```typescript
// 기존 메시지와 병합하면서 중복 제거 (timestamp + sender + text 기준)
setMessages(prev => {
const existingKeys = new Set(
prev.map(m => `${m.timestamp.getTime()}_${m.sender}_${m.text}`)
);
const newMessages = sortedMessages.filter(msg => {
const msgTimestamp = msg.timestamp instanceof Date
? msg.timestamp.getTime()
: new Date(msg.timestamp).getTime();
const key = `${msgTimestamp}_${msg.sender}_${msg.text}`;
return !existingKeys.has(key);
});
// 기존 메시지와 새 메시지를 시간순으로 병합
const merged = [...prev, ...newMessages].sort((a, b) => {
const timeA = a.timestamp.getTime();
const timeB = b.timestamp.getTime();
if (timeA === timeB) {
return a.sender === 'user' ? -1 : 1;
// initialMessages가 있을 때만 병합 방식으로 추가 (덮어쓰기 방지)
if (initialMessages.length > 0) {
setMessages(prev => {
// 기존 메시지가 있으면 병합, 없으면 새로 설정
if (prev.length === 0) {
return initialMessages;
}
return timeA - timeB;
// 기존 메시지와 병합하면서 중복 제거
const existingKeys = new Set(
prev.map(m => `${m.timestamp.getTime()}_${m.sender}_${m.text}`)
);
const newMessages = initialMessages.filter(msg => {
const msgTimestamp = msg.timestamp instanceof Date
? msg.timestamp.getTime()
: new Date(msg.timestamp).getTime();
const key = `${msgTimestamp}_${msg.sender}_${msg.text}`;
return !existingKeys.has(key);
});
// 기존 메시지와 새 메시지를 시간순으로 병합
const merged = [...prev, ...newMessages].sort((a, b) => {
const timeA = a.timestamp.getTime();
const timeB = b.timestamp.getTime();
if (timeA === timeB) {
return a.sender === 'user' ? -1 : 1;
}
return timeA - timeB;
});
return merged;
});
return merged;
});
}
```
**효과**:
- `setMessages(sortedMessages)`의 전체 덮어쓰기 문제 해결
- `handleSend``setMessages(prev => [...prev, robeingMessage])`와 비동기 경쟁 상황에서도 중복 방지
- `setMessages(initialMessages)`의 덮어쓰기 문제 해결
- `handleSend`에서 추가한 메시지와 기본 메시지를 병합하여 중복 방지
- timestamp + sender + text 기준으로 중복 체크하여 같은 메시지가 두 번 추가되지 않음
- 기존 메시지와 히스토리 메시지를 시간순으로 병합하여 정상 표시
---