useState를 통해 상태를 관리하고 state의 변화에 따라 필요한 부분을 리렌더링 시킬 수 있었는데요. 만약 상태를 관리하는 데이터를 필요로 하지만 리렌더링을 발생시키지 않는 값이 필요할 경우는 어떡하지 라는 의문이 들었습니다. 그리고 useRef 라는 hook이 그 해결법을 제시해주었습니다.
useRef
는 렌더링에 필요하지 않은 값을 참조할 수 있는 React hook 입니다. 렌더링 시 재설정되는 일반 변수와 다르게 정보를 저장합니다. state와 동일한 패턴으로 동작하나 렌더링에 관여하지 않는 차이가 있다라고 생각하면 될 것 같습니다. 혹은 리렌더링이 돼도 초기화되지 않는 일반 변수라던지요.
useRef
참조를 선언하기 위해서는 반드시 구성 요소의 최상위 컴포넌트에서 호출해야 합니다.
import { useRef } from 'react';
const App = () => {
const intervalRef = useRef(0);
}
useRef에 제공한 값(0)을 프로퍼티(current)로 가진 객체로 반환합니다.
intervalRef.current : 0
이후 컴포넌트가 리렌더링 되어도 useRef
는 동일한 객체를 리턴합니다.
그리고 다시 current
의 값을 변경하고 저장할 수 있습니다. state 와 비슷하지만 명확한 차이는 앞서 말씀드린 것처럼 참조를 변경해도 다시 렌더링되지 않습니다.
그렇다면 useRef
는 어떨 때 쓰는 것일까요?
공식 문서에 따르면 useRef
는 컴포넌트의 시각적으로 출력되는 데 영향을 주지 않는 정보를 저장 하는데 유용하다고 합니다.
const App = () => {
const intervalRef = useRef<any>(null);
const timeRef = useRef(0);
useEffect(()=> {
const timer = setInterval(() => {
timeRef.current = timeRef.current + 1;
console.log(timeRef.current);
}, 1000);
return () => clearInterval(timer)
},[])
}
timeRef
를 생성합니다.timeRef
값을 1씩 증가시키고 값을 출력시키는 timer
를 생성합니다.import { useRef, useEffect } from 'react';
const App = () => {
const elementRef = useRef();
useEffect(() => {
const divElement = elementRef.current;
console.log(divElement); // <div ref={elementRef}>안녕하세요?</div>
}, []);
return (
<div ref={elementRef}>안녕하세요?</div>
);
}
실제로 useRef
가 가장 많이 활용되는 사례라고 합니다. DOM node 나 react element에 사용할 수 있고 위의 경우 useRef
로 <div>
를 참조할 수 있습니다.
import { useRef } from 'react';
export default function CatFriends() {
const listRef = useRef(null);
function scrollToIndex(index) {
const listNode = listRef.current;
const imgNode = listNode.querySelectorAll('li > img')[index];
imgNode.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
});
}
return (
<>
<nav>
<button onClick={() => scrollToIndex(0)} />
<button onClick={() => scrollToIndex(1)} />
<button onClick={() => scrollToIndex(2)} />
</nav>
<div>
<ul ref={listRef}>
<li>1번 이미지</li>
<li>2번 이미지</li>
<li>3번 이미지</li>
</ul>
</div>
</>
);
}
위의 경우 <ul>
를 참조하는 listRef
속성을 부여했습니다. 참조하기 때문에 <ul>
를 직접 수정할 수 있는 상태가 되고 인터랙션을 부여할 수 있습니다. 내비게이션 바로 해당 elememt로 스크롤을 이동시킬 수도 있고 새로고침 시 스크롤 위치를 유지하는 기능도 구현할 수 있습니다.
실제로 dom node를 직접 제어하고 싶었던 적이 정말 많았는데 useRef
를 통해서 모두 해소된 기분이 드네요. useRef
라면 useEffect
가 마운트과정에서 동작하는 것도 막을 수 있겠다라는 생각이 들었습니다. 얏호 맛있다!