티스토리 뷰

useRef는 컴포넌트 내부에서 직접 DOM을 조작해야 할 때 사용합니다.


React에서도 바닐라 자바스크립트와 마찬가지로 JSX 엘리먼트에 id속성을 부여하고, 자바스크립트로 document.getElementById(id)를 통해서 DOM요소를 조작할 수 있습니다.
그러나 React는 컴포넌트로 이루어져 있고, 컴포넌트는 재사용됩니다. 컴포넌트의 JSX엘리먼트에 id를 부여하면, id는 유일해야 하는데 중복 id를 가진 DOM이 여러개 생기니 잘못된 사용입니다.  

또한 React에서는 state를 사용하여 웹페이지를 쉽게 조작할 수 있습니다.
input의 DOM요소를 가져오고, onChange이벤트로 innerText를 변화시키며 직접 DOM을 조작하지 않아도,
[value, setValue] = useState(''), input에 value속성을 {value}로 주고, onChange이벤트로 setValue(event.target.value)를 주는 정도로 쉽게 구현할 수 있습니다. 가상DOM을 사용하여 효율도 훨씬 좋습니다.

그렇다면 React에서 언제 직접 DOM을 조작해야 할까요?
state로 해결할 수 없을 때입니다. 주로 다음의 경우입니다.

  • 특정 input에 포커스 주기
  • 스크롤 박스 조작하기
  • Canvas 요소에 그림 그리기 등

 

useRef로 스크롤 박스 조작하기

이번에 gptea 프로젝트에서 채팅UI를 구현하면서, 최신 메세지가 리스트의 맨 아래에 있어 리렌더링될 때마다 스크롤이 맨 아래에 위치하도록 구현하기 위해 useRef를 사용했습니다. 관련 코드는 매우 짧습니다.

function Div() {
  const scrollRef = useRef();

  useEffect(() => {
    scrollRef.current.scrollTop = scrollRef.current.scrollHeight - scrollRef.current.clientHeight;
  }, [])

  return <div ref={scrollRef}></div>
}

 

TypeScript에서 useRef는?

function Div() {
  // Ref가 참조할 DOM요소가 HTMLDivElement타입임을 명시
  // 이 부분은 return문이 실행되기 전에 실행된다. 즉, DOM이 생성되기 전이므로 DOM요소를 찾으려고 하면 null이다. 
  // null로 지정하지 않으면 자동으로 undefined가 되는데, 타입이 달라서 오류가 발생한다.
  const scrollRef = useRef<HTMLDivElement>(null); 

  // scrollRef.current는 null일 수 있다.
  // 그러므로 처음에는 optional type으로 ?을 주었는데 할당문의 왼쪽은 optional일 수 없다.
  // 이런 경우에는 단축평가를 사용한다.
  useEffect(() => {
    scrollRef.current && scrollRef.current.scrollTop = scrollRef.current.scrollHeight - scrollRef.current.clientHeight;
  }, []) // 

  return <div ref={scrollRef}></div>
}

그러므로 useRef로 DOM을 조작하기 위해 초기값으로 항상 null을 주어야 합니다.
여기서 HTMLDivElement는 제네릭입니다.

자세한 내용은 다음 포스팅에 잘 나와있습니다. (타입스크립트를 좀 더 익히고 다시 공부하기...)

https://tecoble.techcourse.co.kr/post/2022-10-15-function-overloading/

 

함수 오버로딩

서언 TypeScript에는 Function Overloading 기능이 있습니다. 이번에 Function Overloading…

tecoble.techcourse.co.kr

 

(참고)

고마워 ChatGPT 😄

 

 

 

반응형
댓글