[React] ref로 HTML 엘리먼트에 접근/제어하기

React로 웹 애플리케이션을 개발하다 보면 간혹 React 컴포넌트가 아닌 HTML 엘리먼트에 직접 접근해서 DOM API를 이용해서 제어해야 할 필요가 있는데요. 이번 포스팅에서는 이럴 때 유용하게 사용할 수 있는 React의 독특한 prop인 ref 에 대해서 알아보도록 하겠습니다.

ref prop

React의 ref prop은 HTML 엘리먼트의 레퍼런스를 변수에 저장하기 위해서 사용합니다.

예를 들어, 다음과 같이 <input> 엘리먼트에 ref prop으로 inputRef라는 변수를 넘기게 되면, 우리는 이 inputRef 객체의 current 속성을 통해서 <input> 엘리먼트에 접근할 수 있고, DOM API를 이용하여 제어할 수 있습니다.

<input ref={inputRef} />

useRef

ref prop에는 React API를 이용해서 생성한 current 속성을 갖는 특정 형태의 객체만을 할당할 수 있는데요. 클래스 기반 컴포넌트를 에서는 React.createRef() 함수를, 함수형 컴포넌트에서는 useRef() 훅(hook) 함수를 사용하여 이 객체를 생성할 수 있습니다.

본 포스팅에서는 함수형 컴포넌트를 선호하는 최근 트랜드에 맞게 useRef() 훅(hook) 함수를 사용하여 예제 코드를 작성하겠습니다.

예제 1. input 엘리먼트 제어

ref prop은 여러 가지 HTML 엘리먼트 중에서도 <input>을 제어할 때 많이 사용됩니다.

예를 들어, 버튼을 클릭했을 때, 비활성화(disabled)되어 있던 입력란을 활성화시키며 포커스(focus)를 이동시키는 React 컴포넌트를 작성해보겠습니다.

useRef() 훅(hook) 함수를 사용하여 inputRef 객체를 생성한 후, <input> 엘리먼트의 ref prop에 넘기고 있습니다. 이렇게 해주면 inputRef 객체의 current 속성에는 <input> 엘리먼트의 레퍼런스가 저장됩니다. 따라서 <button> 엘리먼트의 클릭(click) 이벤트 핸들러에서는 inputRef.current로 간단하게 <input> 엘리먼트를 제어할 수 있습니다.

import React, { useRef } from "react";

function Field() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.disabled = false;
    inputRef.current.focus();
  }

  return (
    <>
      <input disabled type="text" ref={inputRef} />
      <button onClick={handleFocus}>활성화</button>
    </>
  );
}

마찬가지 방법으로 입력란을 원래대로 비활성화 시켜주는 버튼도 어렵지 않게 추가로 구현할 수 있습니다.

import React, { useRef } from "react";

function Field() {
  const inputRef = useRef(null);

  function handleFocus() {
    inputRef.current.disabled = false;
    inputRef.current.focus();
  }

  function handleReset() {
    inputRef.current.disabled = true;
    inputRef.current.value = "";
  }

  return (
    <>
      <input disabled type="text" ref={inputRef} />
      <button onClick={handleFocus}>활성화</button>
      <button onClick={handleReset}>초기화</button>
    </>
  );
}

예제 2. audio 엘리먼트 제어

ref prop이 사용되는 또 다른 사례로 audio 엘리먼트 제어를 들 수 있는데요.

예를 들어, 음악 파일의 재생하거나 중지할 수 있는 컴포넌트를 작성해보겠습니다.

import React, { useRef } from "react";
import music from "./music.mp3";

function Player() {
  const audioRef = useRef(null);

  const handlePlay = () => {
    audioRef.current.play();
  };

  const handlePause = () => {
    audioRef.current.pause();
  };

  return (
    <>
      <figure>
        <figcaption>Eyes on You (Sting) - Network 415:</figcaption>
        <audio src={music} ref={audioRef}>
          Your browser does not support the
          <code>audio</code> element.
        </audio>
      </figure>
      <button onClick={handlePlay}>재생</button>
      <button onClick={handlePause}>중지</button>
    </>
  );
}

useRef() 훅(hook) 함수로 audioRef 객체를 생성한 후, <audio> 엘리먼트의 ref prop에 설정해주었습니다. 따라서, 이벤트 핸들러 함수 내에서는 audioRef.current를 통해 <audio> 엘리먼트의 play()pause() 함수를 호출할 수 있습니다.

전체 코드

본 포스팅에서 작성한 코드는 아래에서 직접 확인하고 실행해볼 수 있습니다.

마치며

이상으로 React에서 ref prop를 사용하여 어떻게 HTML 엘리먼트에 직접 접근할 수 있는지에 대해서 알아보았습니다.

ref prop 관련해서 한 가지 주의할 점은 HTML 엘리먼트에 직접 제어하는 것은 JQuery 시절에 주로 쓰이던 imperative(명령형) 방식의 웹 프로그래밍이라는 것입니다. Declarative(선언형) 프로그래밍 패러다임을 기반으로 하는 React를 포함한 모던 자바스크립트 라이브러리에서는 반드시 필요한 경우가 아니라면 이러한 접근 방식은 지양하는 것이 좋습니다.

This work is licensed under CC BY 4.0 CC BY

Discord