React useRef의 다양한 활용 방법(+useCallback과 forwardRef)

🐶·2021년 7월 5일
0

개념 정리

목록 보기
20/41

1. DOM을 참조할 때 활용하기

React로 개발 요구 사항을 충족할 수는 없는 경우가 있다. 아래와 같이 DOM 엘리먼트의 주소값을 활용해야 하는 경우 특히 그렇다.

  • focus
  • text selection
  • media playback
  • 에니메이션 적용
  • d3.js, greensock 등 DOM 기반 라이브러리 활용

React는 이런 예외적인 상황에서 useRef으로 DOM 노드, 엘리먼트, 그리고 리액트 컴포넌트 주소값을 참조할 수 있다. 아래 예시 코드처럼 작성하시면 주소값을 활용할 수 있다.

const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
    <div>
      <input ref={주소값을_담는_그릇} type="text" />
        {/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
        {/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
        {/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
    </div>
  );

자바스크립트에서 특정 DOM을 선택해야 할 때에는 DOM Selector를 사용한다.(ex. document.querySelector)
리액트에서는 render() 메서드에 의해 만들어지는 DOM에 접근하는 방식 으로 ref 를 제공한다. 예를 들어 배송지 정보를 입력 받아야 하는 결제 페이지를 만들 때, 사용자가 휴대번호와 같은 필수 정보를 입력하지 않고 결제하기 버튼을 눌렀다면 ref 를 사용하여 휴대번호 input 창에 focus 할 수 있다. 또는 특정 element 의 크기를 가져오거나 이 요소가 DOM 으로부터 얼마만큼 떨어져 있는지 스크롤의 위치를 구할 수도 있다.

이럴 때 리액트 함수형 컴포넌트에서는 React Hooks 중 하나인 useRef() 함수를 사용한다. (+ 클래스형 컴포넌트에서는 콜백함수를 사용하거나 React.createRef 함수를 사용한다고 한다)

아래 예시 코드를 참고해보자. enter를 입력할 때, 입력하는 위치가 어디냐에 따라 세 가지 경우로 조건문을 나눠 적었다. 입력하는 위치가 첫번째 input 일때는 그 다음 input 박스(두번째 input박스)로 커서가 이동함을 알 수 있다(focus 메소드 사용)

https://codesandbox.io/s/patient-worker-3kzhd?from-embed (출처: 코드스테이츠)

import React, { useRef } from "react";

const Focus = () => {
  const firstRef = useRef(null);
  const secondRef = useRef(null);
  const thirdRef = useRef(null);

  const handleInput = (event) => {
    console.log(event.key, event);
    if (event.key === "Enter") {
      if (event.target === firstRef.current) { 
        // 위의 console.log 결과값으로 event 객체를 뜯어보니 target이라는 속성값이 <input></input> 으로 나온다...!
        // 그리고 firstRef도 콘솔에 찍어보니 {current: <input></input>}라는 객체 타입으로 나온다.
        secondRef.current.focus();
        event.target.value = "";
      } else if (event.target === secondRef.current) {
        thirdRef.current.focus();
        event.target.value = "";
      } else if (event.target === thirdRef.current) {
        firstRef.current.focus();
        event.target.value = "";
      } else {
        return;
      }
    }
  };

  return (
    <div>
      <h1>타자연습</h1>
      <h3>각 단어를 바르게 입력하고 엔터를 누르세요.</h3>
      <div>
        <label>hello </label>
        <input ref={firstRef} onKeyUp={handleInput} />
      </div>
      <div>
        <label>world </label>
        <input ref={secondRef} onKeyUp={handleInput} />
      </div>
      <div>
        <label>codestates </label>
        <input ref={thirdRef} onKeyUp={handleInput} />
      </div>
    </div>
  );
};

export default Focus;

2. 변경은 관리해야 하지만 리렌더링을 발생시키지 않아도 되는 값을 다룰 때 사용하기

일단! const 로 선언한 변수 / useState() hook 으로 생성한 변수 / useRef() hook 으로 생성한 변수 의 차이점을 알아보자.

import { useState, useRef } from 'react'

const Component = () => {
    const a = 1 // 일반 변수
    const [state, setState] = useState() // state 변수
    const ref = useRef() // ref 변수
}

컴포넌트의 생애주기란 DOM에 mount 되고 unmount 되기까지의 과정을 말한다. 함수 컴포넌트는 부모로 부터 전달 받는 props가 변경되거나 자신의 state가 변경되면 re-rendering 이 발생한다.

  • 이 때 내부에서 const 로 선언된 변수는 재선언되고 재할당 된다. 즉 컴포넌트의 생애주기를 통해 유지되지 않고 렌더링 마다 값이 초기화된다.
  • useState() hook 으로 만든 변수는 컴포넌트의 생애주기를 통해 유지되지만 상태값이 변경될 때마다 컴포넌트 리렌더링을 발생시킨다.
  • useRef() hook 으로 만든 변수는 컴포넌트의 생애주기를 통해 유지되지만, .current 프로퍼티의 값이 변경되도 컴포넌트 리렌더링을 발생 시키지 않는다. 아래 예시를 통해 살펴보자

https://codesandbox.io/s/wonderful-joliot-2q28x?fontsize=14&hidenavigation=1&theme=dark (출처: 이화랑블로그)

hello 버튼을 눌렀을 때는 즉시 리렌더링이 일어나지만 집사야 눌러봐 버튼을 눌렀을 때는 리렌더링이 발생하지 않고 내부적으로 ref.current 값은 계속 업데이트 되긴 되다가, 외부적인 이유(ex. state 변경)로 컴포넌트가 리렌더링 되면 그 때 변경된 값이 보여질 뿐이다.

이러한 특성으로 useRef() 로 생성한 ref.current 에 HTMLElement 뿐만 아니라 숫자, 문자열, 배열 등의 값을 할당 할 수 있으며, 컴포넌트 내부에서 변경을 관리해야 하지만 굳이 리렌더링을 발생 시킬 필요는 없을 때 활용할 수 있다.

3. callback ref

useMemo와 비슷한 Hook.
useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.
(업데이트 예정)

4. forwardRef

(업데이트 예정)

참고자료
https://xiubindev.tistory.com/98

https://leehwarang.github.io/docs/tech/2020-11-29-ref.html

https://www.youtube.com/watch?v=t2ypzz6gJm0 (useRef)

https://www.youtube.com/watch?v=_AyFP5s69N4
(useCallback)

https://www.daleseo.com/react-hooks-use-callback/ (useCallback)

profile
우당탕탕 개발일기📝🤖

0개의 댓글