스파르타코딩클럽/과제

채팅 시스템 기록

myinfo7091 2024. 12. 30. 23:21

Supabase 실시간 데이터 타입 불일치 문제

  • 문제: payload.new의 타입이 Message와 맞지 않아 TypeScript 에러 발생.
  • 원인: Supabase의 실시간 이벤트에서 반환된 데이터(payload.new)는 기본적으로 any 타입으로 처리되며, 정의된 Message 타입과 불일치.

 

  • Supabase에서 반환된 데이터 타입을 명시적으로 캐스팅해줌.
const message = payload.new as Message;

 

 

Supabase-React 채팅 메시지 순서 문제 해결

  • 문제: 채팅 모달을 닫았다가 다시 열면 메시지 순서가 뒤섞임. Supabase에서 메시지를 가져오는 과정과 실시간 업데이트 로직에서 발생한 문제로 생각됨.
  • 원인: fetchMessages 함수에서 Supabase 쿼리에 명시적인 order 조건이 빠져 있음. Supabase는 기본적으로 데이터를 삽입된 순서대로 반환하지 않을 수 있음. 또한 새 메시지가 추가될 때 기존 상태 배열에 단순히 추가만 되고 있어 기존에 잘못된 순서로 로드된 메시지와 섞일 가능성이 있음.

 

  • 메시지를 가져올 때 created_at 기준으로 정렬 추가함.
const { data, error } = await supabase
  .from('messages')
  .select('*, users(*)')
  .eq('chatroom_id', chatroomId)
  .order('created_at', { ascending: true });

 

  • 실시간 메시지가 추가될 때 기존 배열과 섞이지 않도록, 업데이트 시 정렬 로직 추가.
const channel = supabase
  .channel(`messages:chatroom_id=eq.${chatroomId}`)
  .on(
    'postgres_changes',
    { event: 'INSERT', schema: 'public', table: 'messages', filter: `chatroom_id=eq.${chatroomId}` },
    (payload) => {
      const newMessage = payload.new as Message;
      setMessages((prev) =>
        [...prev, newMessage].sort(
          (a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
        )
      );
    }
  )
  .subscribe();

 

 

채팅 스크롤 자동 최하단 이동

  • 문제: 채팅 화면에서 새로운 메시지가 추가되거나, 컴포넌트가 처음 렌더링될 때 메시지 리스트가 자동으로 최하단으로 스크롤되지 않음. 사용자 경험 문제.

 

  • useRef를 활용한 메시지 리스트 끝부분 참조 생성 (behavior 옵션에 따라 smooth, auto 등 스크롤 속도 변경 가능!)
const messageEndRef = useRef<HTMLDivElement | null>(null);

// ----- (중략) ----- //

useEffect(() => {
  if (messageEndRef.current) {
    messageEndRef.current.scrollIntoView({ behavior: 'smooth' });
  }
}, [messages]); // messages가 변경될 때마다 실행