HTML을 작성할 때, div 등의 DOM 요소에 이름을 달 경우 id 속성을 이용하는 것처럼, 리액트에서도 DOM을 선택해 직접 접근하기 위해 ref를 사용한다.

리액트 컴포넌트 안에서는 특수한 경우가 아니라면 id의 사용을 권하지 않는다. HTML에서 id는 유일해야 하는데, 컴포넌트를 재사용할 때마다 중복 id를 가진 DOM이 여러 개 생겨나기 때문이다. 그래서 리액트에서는 DOM에 이름을 달기 위해 ref를 사용한다.

Ref는 특히, state로만 해결할 수 없고 DOM을 반드시 직접 건드려야 할 때 사용하게 된다.

특정 input에 focus를 준다거나, 스크롤 박스를 조작하는 등의 일이 필요할 때 사용한다. 이를 비제어 컴포넌트를 제어하는 경우라고 하는데, 리액트 시스템 내에서 제어하지 않고 순수 자바스크립트를 이용해 컴포넌트를 제어하는 경우를 말한다.

만약 입력창의 값을 state로 관리하게 되면 값이 바뀔 때마다 state가 바뀌고, 이로 인해 불필요한 리렌더링이 반복적으로 발생하게 된다. 이 문제를 해결하기 위해 입력창에 ref를 달아 주면 입력창의 값을 state로 관리하지 않더라도 외부에서 입력창의 값에 접근할 수 있게 된다.

Ref를 콘솔에 나타내 보면 {current: null} 이라는 Reference 객체가 나온다. 리액트는 이 객체를 통해 DOM에 직접적인 접근을 가능하게 한다. Ref.current 는 Ref가 현재 참조하고 있는 DOM 요소이다.

또한, Ref는 전역적으로 작동하지 않고 오직 컴포넌트 내부에서만 작동한다.

image.png

useRef 사용하기

리액트에서는 useRef라는 리액트 함수를 이용하여 Ref 객체를 생성한다.

useRef는 새로운 Reference 객체를 생성한다.

이 함수를 사용하려면 리액트 라이브러리에서 useRef를 불러와야 한다.

import { useRef, useState } from "react";

function Body() {
  const [text, setText] = useState("");
  const textRef = useRef();

  const handleOnChange = (e) => {
    setText(e.target.value);
  };
  const handleOnClick = () => {
    alert(text);
  };

  return (
    <div>
      <input ref={textRef} value={text} onChange={handleOnChange} />
      <button onClick={handleOnClick}>작성 완료</button>
    </div>
  );
}
export default Body;

useRef로 입력 폼 초기화하기

웹서비스의 로그인 페이지는 대부분 사용자가 ID와 패스워드를 입력하고, 로그인 버튼을 클릭하면 패스워드가 올바른지 점검한다. 그런 다음 패스워드 입력 폼에서 작성한 값을 초기화한다. 리액트에서 Ref를 이용하면 이 동작을 수행할 수 있다.

import { useRef, useState } from "react";

function Body() {
  (...)
  const handleOnClick = () => {
    alert(text);
    textRef.current.value = "";
  };
  (...)
}
export default Body;

위 예제 코드에서 handleOnClick() 함수를 다음과 같이 수정한다. textRef.current는 Ref가 현재 참조하고 있는 DOM 요소다. 그 요소의 value 값을 빈 문자열 공백으로 초기화하면 입력 폼을 초기화할 수 있다.