채팅 내역 불러오기 및 실시간 업데이트

채팅 내역 Realtime Database에서 불러오고 실시간 업데이트를 하도록 구현 완료했다!

Realtime DB의 onValue 메소드를 이용하면 쉽게 구현할 수 있었다.

 

export function getChatHistory(chatRoomNum) {
    return ref(database, '/ChatRooms/' + chatRoomNum + '/ChatMessages/');
}

ref를 이용해서 DB 경로를 지정하고

 

import { onValue } from '@firebase/database';

const ChatRoom = (props) => {
	...
    const chatHistoryRef = getChatHistory(chatRoomNum);

    useEffect(() => {
        onValue(chatHistoryRef, (snapshot) => {
            let chatFromFB = []
            snapshot.forEach((chatDate) => {
                chatDate.forEach((chat) => {
                    const content = chat.val().content;
                    const senderId = chat.val().senderId;
                    const time = chat.val().time;
                    chatFromFB.push({content, senderId, time});
                })
            })
            setChatHistory(chatFromFB);	//상태 업데이트 -> 리렌더링
        });
 	...

채팅 내역을 불러올 js의 useEffect에서 onValue 메소드를 작성해주면 지속적으로 업데이트가 된다.

Firestore을 이용해서 전체 조회를 할 수 있도록 그렇게 고민을 했었는데 이렇게 쉽게 만들 수 있는거였다니...🥺

 

forEach로 돌릴 수 있게 되어서 각 날짜 별 채팅 가장 상단에 날짜를 표시하면 좋겠다 싶어서 ChatDateLine.js를 새로 만들고

 

{
    this.state.chatHistory.map((value, i) => {
        if (!value.senderId){
            return (
                <ChatDateLine key={i} year={value.year} month={value.month} date={value.date}/>
            )
        } else if (value.senderId == this.props.loginId){
            return (
                <SendChatMessage key={i} content={value.content} time={value.time}/>
            );
        } else {
            return (
                <ReceiveChatMessage key={i} content={value.content} time={value.time} friendName={this.friendName}/>
            );
        }
    })
}

JSX 안에서 조건부 렌더링을 하는데

수신자 아이디가 없으면 날짜를, 아이디가 현재 로그인한 아이디와 같으면 내가 보낸 메세지로,

아이디가 다르면 받은 메세지를 출력하도록 한 것이다.

map을 할 때는 유니크한 key를 지정해주는 것을 잊지 말자!

 


 

채팅 자동 스크롤 & react-custom-scrollbars을 이용한 커스텀 스크롤

일반적으로 채팅방에 입장했을 때, 내가 채팅을 전송했을 때 채팅의 가장 아래 부분으로 자동 스크롤이 된다.

이것을 구현하기 위해 여러 방법을 시도해보았는데

useEffect 안에서 상태 업데이트 후 스크롤 코드를 작성했더니 마지막 메세지 바로 위까지만 스크롤이 되는 것이다.

 

이것은 상태가 바뀌기 전의 렌더링 상태에서 스크롤 높이 계산을 하기 때문이었고

결국 클래스형 컴포넌트의 ComponentDidUpdate 라이프 사이클 함수를 사용하기 위해

함수형 컴포넌트를 클래스형 컴포넌트로 변경하는 수정 작업을 해야했다.

 

클래스형 컴포넌트로 변경하면서

1. useSelector 대신 connect 함수와 mapStateToProps 이용

2. useRef 대신 createRef 이용

3. 상태를 변경하기 위해 useState 대신 setState 이용

4. constructor 작성 등

수정할 부분이 은근히 많아서 시간이 꽤 걸렸다.

 

 

수정을 완료한 후에는 HTML의 기본 스크롤이 너무 투박해보여서 react-custom-scrollbar 라이브러리를 적용했다.

 

https://github.com/malte-wessel/react-custom-scrollbars

 

GitHub - malte-wessel/react-custom-scrollbars: React scrollbars component

React scrollbars component. Contribute to malte-wessel/react-custom-scrollbars development by creating an account on GitHub.

github.com

 

스크롤 모양도 훨씬 나아졌고 autoHide 속성을 이용해서 일정 시간이 지나면 자동으로 스크롤을 숨길 수 있었다.

자동 스크롤은 scrollToBottom() 메소드를 이용해서 구현할 수 있었다.

 

 

이 라이브러리를 이용하다보니 자동으로 가로 스크롤도 생성이 되길래 이것을 없애는 방법을 찾아보았고

 

https://github.com/malte-wessel/react-custom-scrollbars/issues/213

 

How to disable the horizontal scrollbar? · Issue #213 · malte-wessel/react-custom-scrollbars

 

github.com

해당 issue에 나온 첫번째 답변대로 renderTrackHorizontal 속성 안의 style에서 display: 'none'을 지정하여 해결했다.

다른 답변처럼 overflowX: 'hidden'도 작성해보았는데 이것은 작동하지 않았다.

 


기타 수정 사항

1. 채팅방 입장 시 input 박스에 focus 주기

2. 엔터키 입력 시 채팅 전송하기

3. input 박스가 전송 버튼에 가려지지 않도록 수정

 

개선해야할 사항

채팅방 팝업 띄우는 부분을 window.open으로 작성했는데,

창 크기를 고정하기 위해 resizeable=no 옵션을 추가했지만 적용되지 않길래 찾아봤더니

 

https://stackoverflow.com/questions/15480252/make-window-not-resizable-in-chrome/15481333

 

Make window not resizable in Chrome

I have some JavaScript that I use to make a window not resizable, something along the lines of: window.open(URL, id, "resizable=no"); This works in most browsers but it appears to not be supporte...

stackoverflow.com

이것은 IE에서만 작동하는 옵션이고, 최신 브라우저는 지원하지 않는다고 한다.

window.open 자체가 old school JS라며 다른 방법을 이용할 것을 권장하는 것으로 보인다.

새로운 창을 띄우는 라이브러리들도 존재하는 것 같은데 다음에 자세히 찾아봐야겠다.

 


 

크롬과 엣지에서 다른 계정으로 접속하고 채팅을 보낸 것이다. 제대로 작동한다~

채팅 기능이 완성되어서 친구들에게 배포할 수 있는 상태가 되긴 했으나

아직 레이아웃 보완 또는 세부적인 기능 구현할게 많이 남아있어서 천천히 배포할 생각이다ㅎㅎ

오늘 열심히 개발해서 뿌듯

+ Recent posts