본문 바로가기
Dev/react

자동 스크롤 문제 해결 / scrollTop = scrollHeight 적용 안됨

by 혜옹쓰 2022. 9. 22.

문제 발생

  • 채팅창을 구현하며 채팅을 입력했을 때 자동으로 채팅창 가장 하단으로 스크롤이 내려가도록 하는 기능을 구현하게 됨
document.getElementsByClassName('class').scrollTop 
	= document.getElementsByClassName('class').scrollHeight
  • 스크롤 높이를 사용하여 조작하려고 시도했지만 가장 최신 채팅이 아닌 아래서 두번째 채팅을 기준으로 스크롤링됨
  • → 콘솔을 찍어봤을 때 scrollTop 과 scrollHeight 의 값이 같게 적용되지 않았음. 하지만 이게 정확한 원인인지 파악할 수 없음

해결 과정

  • DOM 을 직접 수정하는 방법을 적용할 수 없기 때문에, ref 를 사용하여 적용해보기로 함
  • 전채 채팅을 감싸고 있는 ‘chat-list’ 에 boxRef 를 주고, 그 내부에 빈 div 태그를 만들어 scrollRef 를 주었음
  • → boxRef 의 높이를 스크롤 높이와 비교하여 가장 아래에 있는 빈 div 태그 기준으로 스크롤이 내려갈 수 있도록 함.
export default function LiveDetail() {

	// NOTE 스크롤 자동 이동
  useEffect(() => {
      if (chatListRef.current.offsetHeight < chatListRef.current.scrollHeight)
          return scrollRef.current.scrollIntoView({ behavior: 'smooth' });
  }, [chattings]);

	return (
		// ...
		<div
        className="chat-list"
        style={{
            height: `${
                pinValue || pinValue === 0 ? 'calc(762px - 72px - 40px)' : 'calc(762px - 72px)'
            }`,
        }}
        ref={chatListRef}
    >
        {chattings.map((c, index) => (
            <Chatting
                data={c}
                chattings={chattings}
                setStateChattings={setStateChattings}
                key={index} // TODO
            />
        ))}
        <div ref={scrollRef} />
    </div>
		// ...
	)
}

⇒ offsetHeight 는 margin 이나 padding 을 고려한 높이. 하지만 테스트 해봤을 때 정상적으로 작동했음?

⇒ 조건문의 의미는 감싸고 있는 요소의 높이보다 채팅이 추가되어 늘어난 요소의 스크롤 높이가 높은 경우 가장 아래 두었던 스크롤 기준으로 스크롤됨. behavior 옵션으로 스크롤 애니메이션을 적용할 수 있음

⇒ 채팅이 생길 때마다 스크롤이 옮겨져야 하기 때문에 useEffect dependency 에 넣어줌