'(prev: { chatroom_id: string; content: string; created_at: string; id: string; sender_id: string; }[]) => ({ chatroom_id: string; content: string; created_at: string; id: string; sender_id: string; } | { ...; })[]' 형식의 인수는 'SetStateAction<{ chatroom_id: string; content: string; created_at: string; id: string; sender_id: string; }[]>' 형식의 매개 변수에 할당될 수 없습니다.
payload.new의 타입이 정확히 지정되지 않았기 때문에 에러가 발생한다. payload.new가 Supabase의 postgres_changes 이벤트로 전달된 데이터인데, 타입 추론이 제대로 이루어지지 않았다.
payload.new에 타입 지정하기 payload.new는 Message 타입으로 지정해줄 것이다. as Message를 사용하여 명시적으로 타입을 단언해줄 수 있다.
// Supabase Realtime 구독 설정
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]); // 새 메시지 추가
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, [chatroomId]);
수정한 전체 코드
'use client';
import { Database } from '@/types/supabase';
import { createClient } from '@/utils/supabase/client';
import { useEffect, useState } from 'react';
type Message = Database['public']['Tables']['messages']['Row'];
const ChatRoom = ({ chatroomId }: { chatroomId: string | null }) => {
const supabase = createClient();
const [messages, setMessages] = useState<Message[]>([]);
const [message, setMessage] = useState<string>('');
useEffect(() => {
// 채팅방의 메시지 조회
const fetchMessages = async () => {
const { data, error } = await supabase.from('messages').select('*, users(*)').eq('chatroom_id', chatroomId);
console.log(data);
if (error) {
console.error('메시지 불러오기 실패:', error);
} else {
setMessages(data);
}
};
fetchMessages();
// Supabase Realtime 구독 설정
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]); // 새 메시지 추가
}
)
.subscribe();
return () => {
supabase.removeChannel(channel);
};
}, [chatroomId]);
// 메시지 전송
const handleSendMessage = async () => {
if (!message.trim()) return;
const { error } = await supabase.from('messages').insert({
chatroom_id: chatroomId,
sender_id: '5fdcaeb3-b543-442f-9dfd-fafbb1c1b2bc', // 현재 로그인된 사용자 ID 필요
content: message
});
if (error) {
console.error('메시지 전송 실패:', error);
} else {
setMessage('');
}
};
return (
<div className="p-4 flex flex-col h-full">
<h3 className="text-lg font-semibold mb-4">채팅방</h3>
<div className="flex-1 overflow-y-auto">
{messages.map((message) => (
<div key={message.id}>
{message.id}: {message.content}
</div>
))}
</div>
<div className="flex items-center p-2 border-t">
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="메시지를 입력하세요..."
className="flex-1 px-4 py-2 border rounded-lg focus:outline-none"
/>
<button
onClick={handleSendMessage}
className="ml-2 px-4 py-2 bg-blue-500 text-white rounded-lg focus:outline-none"
>
전송
</button>
</div>
</div>
);
};
export default ChatRoom;
'스파르타코딩클럽 > 내일배움캠프' 카테고리의 다른 글
채팅방-갤러리 탭 분리하기 (0) | 2025.01.14 |
---|---|
Zustand 모달 open/close (0) | 2024.12.27 |
렌더링 패턴 (0) | 2024.12.17 |
[Typescript] (1) | 2024.12.12 |
[Next.js] 주요 렌더링 패턴 (1) | 2024.12.10 |