Firebase - Channel Message기능 구현하기(6)

데이터베이스에 Messages 저장하기

채널을 개설하면 그 안에서 채팅을 할 수 있는 기능을 구현할 것이다. 각각의 채팅은 messages라는 collection에 저장되고, messages에서 데이터를 가져와 채팅창 화면을 보여분다.

Messages 스키마

messages collection 밑에 각각의 채널을 구분하는 고유 key가 있고 채널 밑에는 message document가 있다.

{
    messages : [
        uniqueChannelId: [
            message1,
            message2,
            ...
        ]
    ]
}

channel5

이런 식으로 message가 저장될 것이다.

child().push().set()

push() unique한 새로운 child 위치에 대한 reference를 반환한다. 여기에 데이터를 추가하는 메소드인 set()과 함께 쓰이면 child 위치에 고유 key를 생성하면서 그 key밑에 데이터를 생성하는 것이다.

const messagesRef = firebase.database().ref("messages"); // messages 레퍼런스 생성

messagesRef.child(채널 고유 key).push().set(메시지)

실제 메시지를 데이터베이스에 저장하는 함수를 작성하면 다음과 같이 작성할 수 있다.

/*
    type Messasge = {
        content: string
        timestamp: Date
        user: User
    }

*/
const sendMessage = (channelId, message) => {
  messagesRef
    .child(channelId)
    .push()
    .set({
      ...message,
      // timestamp를 client쪽에서 추가해준다.
      timestamp: firebase.database.ServerValue.TIMESTAMP,
    })
    .then(() => {
      // 성공
    })
    .catch(() => {
      // 실패
    });
};

컴포넌트에서 message 저장하기

컴포넌트에서 메시지를 데이터베이스에 저장하기 위해서는 먼저 사용자의 입력을 받을 수 있는 form이 있어야 한다. 그리고 사용자의 입력을 담을 수 있는 state도 필요할 것이다. 보내기 버튼을 클릭하면 메시지가 데이터베이스에 전송할 수 있도록 onClick 헨들러로 방금 정의한 함수를 달아야 할 것이다.

// MessageFormContainer.jsx

const currentChannel = useSelector((state) => state.channel.currentChannel);
const [message, setMessage] = useState(null);

// MessageForm.jsx

return (
  // ...

  <form>
    {/*....*/}
    <button onClick={() => sendMessage(currentChannel.id, message)}>
      메시지 전송
    </button>
  </form>
);

물론 위 코드는 뼈대만 작성한 것이다.

데이터베이스에서 Messages 가져오기

on(“child_added”)

message를 데이터베이스에 저장하면 새로 추가된 message를 가져와 채팅창 화면에 보여줘야 할 것이다. on("child_added") 를 통해서 messages 에 리스너를 달아준다.

const [messages, setMessages] = useState([]);

useEffect(() => {
  let loaded = [];
  messagesRef.child(currentChannel.id).on("child_added", (snap) => {
    loaded.push(snap.val());
    setMessages([...loaded]);
  });
}, []);

데이터베이스에서 가져온 messages는 state로 관리하게 되고 이를 화면에 보여준다.

{
  messages.map((m) => <Message />);
}