채팅 메시지 전송 기능 리팩토링 Optimistic

JeongChan·2025년 7월 9일

Troubleshooting

목록 보기
5/6
post-thumbnail

앞서 realtime 구조를 다시 확립하였는데 이 과정 후 UI에 메시지를 전송하고 랜더 되는 과정에 3초 정도 지연되어 표시되는 문제가 발생했다.

메시지를 전송 → Realtime → invalidate → fetch → 렌더

DB에 인식되어 Realtime 을 거쳐 React Query 로 오는 과정에 시간이 많이 걸려 진 것이다.


📌 리팩토링 스토리


📚 제시: 리펙토링할 기능

기존 구조는 사용자가 메시지를 보내면 서버에 저장되고, Supabase Realtime이 변경 사항을 감지하여 클라이언트에 전파하고, 그 후 React Query가 메시지를 다시 불러오는 구조였다.

하지만 이 방식은 전송 후 메시지가 3~4초 지연되어 표시되는 UX 문제를 발생시켰다.

📚 전략:

  • Realtime 메시지 반영을 빠르게 보여주기 위해 Optimistic UI를 도입하기로 결정했다.
  • 메시지를 전송하기 전에 미리 화면에 렌더링하고, 실패 시 롤백하는 방식으로 UX를 개선한다.
  • Supabase Realtime은 여전히 변경 감지용으로 사용하지만, 주요 상태 관리는 React Query 캐시로 일원화한다.

ChatInput 리펙토링


useSendMessage 훅에 Optimistic Update 적용


📚 문제: 리팩토링 중 발생한 문제들

  • mutation 객체 없음 오류
  • uuid 관련 zod 혼동 (zod.v4uuid 설치 필요)
  • 타입 에러 (ZodUUID is not assignable to string 등)
  • useMutation의 generic 파라미터 누락으로 타입 추론 실패
  • onMutate에서 undefined 가능성 제거 안 해서 타입 충돌

📚 참고한 Reference

TanStack Query 공식 문서 - optimistic

Supabase Realtime Docs

uuid - npm


📚 결론 & 교훈

  • 메시지를 즉시 렌더링하면서도 안정적으로 서버 데이터와 동기화되는 구조를 만들 수 있었다.
  • Realtime 시스템은 "알림" 역할로만 쓰고, 상태는 React Query에서 관리하는 아키텍처가 더 예측 가능하고 유연하다는 걸 배웠다.
  • 타입스크립트를 사용할 때에는 훅에 정확한 generic 타입을 지정하는 것이 예상치 못한 타입 오류를 막는 핵심이라는 교훈을 얻었다.
  • 사용자의 UX 관점에서 1~2초의 지연도 체감 차이가 크다는 걸 다시 느끼며 Optimistic UI가 얼마나 중요한지 실감할 수 있었다.




📌 마무리

실시간 기능에 대해 개선할 점은 무궁무진 하다고 생각된다.
사용자와 사용자가 작용하는 기능이여서 신경 써야할 부분도 두 배로 많아 진 것 같다.
직접 쓸때는 몰랐지만 구현 하려니 아직 까지도 개선되어야 할 부분이 많이 보인다.
후 에 작업하고 개선된 내용도 작성할 계획이다.

profile
Development Notes

0개의 댓글