second code challenge는 라이브 채팅이다.
뭐 라이브 채팅은 간단하게 라이브 스트리밍에 + 라이브 채팅 기능을 추가했다
이전에 했던 supabase를 사용해서 라이브 채팅을 구현했다. 
간단하게 채팅을 입력할 수 있는 Input은 하단에 고정을 해두었고, 채팅은 7개만 화면에 보이고 7개 이상은 저기 ・・・ 버튼 속에 들어간다! 저 버튼을 눌러아 이전에 했던 채팅들을 모두 볼 수 있게 해두었다.
우선 따로
<LiveStreamChat/> 컴포넌트를 생성했고, 이 컴포넌트에서는 데이터를 불러오는 역할을 했다.
async function getLiveStream(id: number) {
return await db.liveStream.findUnique({
where: { id },
select: { userId: true },
});
}
async function getUserProfile() {
const session = await getSession();
const user = await db.user.findUnique({
where: {
id: session.id,
},
select: {
username: true,
avatar: true,
},
});
return user;
}
async function getLiveStreamChat(id: number) {
const liveStreamChat = await db.liveChatMessage.findMany({
where: {
streamId: id,
},
select: {
payload: true,
userId: true,
created_at: true,
user: {
select: {
username: true,
avatar: true,
},
},
},
});
return liveStreamChat;
}
export type InitialChatMessages = Prisma.PromiseReturnType<
typeof getLiveStreamChat
>;
// LiveStreamChat 컴포넌트
export default async function LiveStreamChat({ id }: { id: number }) {
const liveStreamChat = await getLiveStreamChat(id);
const liveStream = await getLiveStream(id);
const session = await getSession();
if (!liveStreamChat || !liveStream) {
return notFound();
}
const user = await getUserProfile();
if (!user) {
return notFound();
}
return (
<div className="mt-5">
<LiveStreamMessageForm
id={id}
initialMessages={liveStreamChat!}
userId={liveStream.userId}
username={user.username}
avatar={user.avatar!}
/>
</div>
);
}
getLiveStream, getUserProfile, getLiveStreamChat으로 각각 라이브 스트리밍의 생성자를 받아오고, 로그인한 사용자의 정보를 받아오고, 데이터에 저장된 채팅들을 모두 불러왔다. 또한, 데이터에 저장된 채팅들을 liveStreamChat으로 저장한 뒤, initialMessages에 보내주었다.
왜 ? --> 라이브 채팅이 되기 이전 이미 전달된 메시지이기 때문에 화면에 뿌려줄 메시지들을 저장을 해둔 것이라고 생각하면 된다.
채팅을 구현하기 위해
스트리밍의 id, 기존의 메시지들을 저장한 initialMessages, 라이브 스트리밍을 하고 있는 UserId, 현재 로그인한 user의 username과 avatar로 생각하면 될 것 같다!
이것을 이제 <LiveStreamLiveChat/> 에서 구현을 해볼 것이다.
이렇게 이전과 동일하게 supabase에 채널을 연결(구독)을 하고,
폼을 제출할 때, 이전의 prevMessages (이것은 initialMessages이다)에 새로운 newMsg를 추가해 주었다.
추가해 준 message들을
saveLiveChatMessage를 통해서 DB에 저장도 해주었다.
여기 LiveStreamMessageForm() 에서 사용한 messages는 initialMessages에서 초기화를 시켜준 것이고, 새로 입력한 메시지를 message에 저장해 두었고,
showAllMessages는 이전에 이야기 한 전체 메시지를 보기 위한 상태를 설정하기 위함이라고 생각하면 될 것이다.
const channel = useRef<RealtimeChannel>()는 참조 객체(ref) 를 생성하고, 이 객체를 통해 RealtimeChannel에 대한 직접적인 참조를 유지하는 역할을 하게 된다.
--> channel은 RealtimeChannel 객체에 대한 참조를 저장한다.
channel.current는 실제 RealtimeChannel 객체를 가리키게 된다.
이 방식으로 Supabase에서 생성한 실시간 채널에 대한 참조를 유지하고, 컴포넌트가 다시 렌더링될 때도 이 채널에 계속 접근할 수 있도록 하는 것이 목적이다.
(ref는 다시 랜더링이 되더라도 데이터가 유지되는 이점을 가지고 있기 때문)
그럼 메시지 7개 이상이 되면 더보기 버튼이 생기고, 더보기 버튼을 누르면 전체 메시지를 볼 수 있게 되는 것은 어떻게 할 까?
!showAllMessages: showAllMessages가 false일 때, 즉 모든 메시지를 보여주지 않는 상태일 때 더보기 버튼을 보여주었다.
버튼을 클릭하면 setShowAllMessages의 상태가 true로 변하게 되면서, 버튼이 보이게 되는데,
const displayedMessages = showAllMessages ? messages : messages.slice(-7);
showAllMessages가 true일 때: 전체 메시지를 보여준다,
showAllMessages가 false일 때: 최신 7개의 메시지만 보여주도록 displayedMessages에 설정을 해두었고,
--
거의 이틀하고 반이 걸린 대장정이 끝났다!!!!!!!!!!!!!!!!!!!!!!!으아아아아앍 딱 이 표정과 이 마인드이다.
이제 거의 강의가 80퍼가 끝났다.
next.js 프로젝트 캠프가 시작하기 전에 요 캐럿 마켓을 마무리 하고 싶은데 가능할지 모르겠다..
하핫.. 인생 쓰다