[TIL]React Hooks - useRef

ddoni·2021년 3월 6일
1
post-thumbnail

useRef

개념

자바스크립트에선 getElementById, querySelector 등을 사용하여 html 돔 요소에 접근 가능하여 요소의 속성값을 바꾸는 것이 가능했다.

--html--
<div>Hi!</div>
--html--

//JS에서 HTML파일의div 요소에 접근하는 방법
const div = document.querySelector("div");

setTimeout(() => {
	div.innerText = "Bye!";
}, 2000)

리액트 함수형 컴포넌트에선 Ref API를 사용하여 useRef hook을 이용하여 돔 요소에 접근할 수 있다. (특정 요소의 크기를 선택, 스크롤바의 위치를 가져와서 설정해야 하는 경우 등등)

export const UseRefPractice: React.FC = () => {
  //useRef의 제네릭에 담고자 하는 값의 타입을 넣어준다
  //인자(초기값)로 보통 null이 전달된다. 
 //(null을 넣어주는 이유 : 명시적으로 빈 레퍼런스가 생성되었음을 알려 주기 위해)
  const divRef = useRef<HTMLDivElement>(null);
  console.log("컴디마 전의 ref 값", divRef); //null 이 출력

  useEffect(() => {
    //컴포넌트 내에서 useRef의 반환 값을 사용할 땐 null check가 필수이다.
    //실제 ref에 요소가 담기는 시점은 컴디마에서 담기므로 null check를 해준다. 
    //(이 체크를 해주지 않으면 TS error가 뜬다)
    setTimeout(() => {
      if (divRef && divRef.current) {
        divRef.current.innerText = "Bye!";
        console.log("컴디마 이후의 ref 값", divRef); //div 출력
      }
    }, 2000);
  }, []);

  return (
    <div>
      <h4>Welcome to visit our website!😉</h4>
      <div ref={divRef}>Hi!</div>
    </div>
  );
};

어떻게 값이 useRef에 담기는지?

React의 Ref 변수는 변경 가능한 객체이지만 값은 다시 렌더링하는 동안 React에 의해 유지된다. ref 객체는 이름이 current인 하나의 프로퍼티를 가지고 구조는 { current: ReactElementReference } 와 같다. 컴포넌트의 리렌더링 동안, DOM 요소는 그 동안 업데이트를 받게 된다. 그리고 DOM 요소에 있는 ref 또한 업데이트를 받게 된다. ref가 있는 요소가 업데이트 되지 않는 경우 ref는 유지된다.

useRef에 값 저장하기

useRef는 DOM references 대신 값을 저장하는 방법으로도 사용 될 수 있다(변수를 관리하는 역할). useRef에 저장되는 값은 너무 자주 바뀔 필요가 없거나 자주 변경되지만 컴포넌트의 전체를 리렌링하지 않는 상태인 경우에 해당한다. useRef 로 저장되는 값은 컴포넌트를 리렌더링하지 않고 설정 후 바로 조회 할 수 있으므로 아래의 경우에 사용하는 것이 유용하다.

export const UseRefPractice = () => {
  let isClicked = useRef(false);
  console.log("클릭이벤트 전의 상태", isClicked);

  const clickHandler = () => {
    //클릭이벤트에 따라 ref 값은 변경된다
    isClicked.current = !isClicked.current;
    console.log("클릭중", isClicked);
  };

  return (
    <section>
      <h3 onClick={clickHandler}>This is Title</h3>
      {/* ref 상태 값은 변경되지만 리렌더링이 이루어지지 않으므로 
					ref값에 따라서 리턴되는 결과엔 영향을 주지 않는다.
      -> refs는 컴포넌트의 라이프사이클에서 같은 값을 홀드하기 때문이다 */}
      {isClicked && <p>It's Clicked!</p>}
    </section>
  );
};
  • setTimeoutsetInterval 을 통해서 만들어진 id
  • 외부 라이브러리를 사용하여 생성된 인스턴스
  • scroll 위치

useRef 이용하여 스크롤 위치 구하기

export const UseRefPractice = () => {
  const divRef = useRef<HTMLDivElement>(null);

  const scrollingToTop = () => {
    if (divRef && divRef.current) {
      divRef.current.scrollIntoView({ behavior: "smooth" });
    }
  };

  return (
    <div ref={divRef}>
      <ListContainer>
        {MENU_LIST.map((menu, idx) => {
          return <li key={idx}>{menu.menu}</li>;
        })}
      </ListContainer>
      {MENU_LIST.map((src, idx) => {
        return <Img alt={src.menu} src={src.src} key={idx} />;
      })}
      <button onClick={scrollingToTop}>TOP!</button>
    </div>
  );
};

참고자료

A Thoughtful Way To Use React's useRef() Hook - Smashing Magazine

TypeScript and React: Hooks

0개의 댓글