[React] useRef 를 사용해보자.

hyunwoo Jin·2023년 5월 14일
0
post-thumbnail
post-custom-banner

useState를 통해 상태를 관리하고 state의 변화에 따라 필요한 부분을 리렌더링 시킬 수 있었는데요. 만약 상태를 관리하는 데이터를 필요로 하지만 리렌더링을 발생시키지 않는 값이 필요할 경우는 어떡하지 라는 의문이 들었습니다. 그리고 useRef 라는 hook이 그 해결법을 제시해주었습니다.

useRef?

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컴포넌트의 시각적으로 출력되는 데 영향을 주지 않는 정보를 저장 하는데 유용하다고 합니다.

example 1


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를 생성합니다.
  • useEffect 내 1초마다 timeRef 값을 1씩 증가시키고 값을 출력시키는 timer를 생성합니다.
  • 그리고 useEffect 의 cleanup 로 컴포넌트가 언마운트될 때 매초 반복작업하던 timer 함수를 제거합니다.

example 2

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>를 참조할 수 있습니다.

example 3

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가 마운트과정에서 동작하는 것도 막을 수 있겠다라는 생각이 들었습니다. 얏호 맛있다!

profile
꾸준함과 전문성
post-custom-banner

0개의 댓글