react.js

useRef 사용법 정리

HTML과 JavaScript를 사용할 때, 특정 DOM을 선택해야 하는 상황에서 어떤 메서드를 사용하는가?

바로 DOM 함수인 getElementById(), querySelector() 를 사용한다.

 

React를 사용하는 프로젝트에서도 가끔 DOM을 직접 선택해야 하는 상황이 발생할 수 있다.

예를 들어, 특정 Element의 크기위치를 가져와야 할 때, 스크롤바 위치를 가져오거나 설정해줘야 할 때, focus를 설정해줘야 할 때 등, 다양한 상황이 있다. 또한 video.js, jw player와 같은 HTML5 비디오 관련 라이브러리를 사용할 때나 D3, chart.js 같은 그래프 관련 라이브러리를 사용하게 될 때도 특정 DOM에 라이브러리를 적용하기 때문에 DOM을 선택해야 하는 상황이 발생할 수 있다.

 

이때, ref를 활용한다!

 

함수형 컴포넌트에서 ref를 사용할 때는 useRef Hook을 사용한다.

클래스형 컴포넌트에서 ref를 사용할 때는 React.createRef()를 사용하거나 콜백함수를 사용한다.

 

본 포스팅은 함수형 컴포넌트에서 useRef Hook을 사용하여 특정 DOM을 선택하는 방법에 대해 알아볼 것이다.

 


#예제1

import React, { useState } from 'react';

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    nickname: '',
  });
  const { name, nickname } = inputs;

  const onChange = (e) => {
    const { name, value } = e.target;

    setInputs({
      ...inputs,
      [name]: value,
    });
  };
  const onReset = () => {
    setInputs({
      name: '',
      nickname: '',
    });
  };

  return (
    <div>
      <input
        name="name"
        placeholder="이름"
        onChange={onChange}
        value={name}
      />
      <input
        name="nickname"
        placeholder="닉네임"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;

위 코드를 그대로 작성했을 때 초기화 버튼을 누르게 되면, focus 되는 부분은 초기화 부분이다. focus 되는 부분을 다른 곳으로 이동시키고 싶을 때, React 자체적인 기능으로는 딱히 할 수 있는 방법이 없다.

이럴 때는 어쩔 수 없이 DOM에 직접 접근해야 한다.

 

 

1. useRef 사용법

// 1. useRef 작성
import React, { useState, useRef } from 'react';

// 2. ref 객체 생성
const nameInput = useRef();

// 3. 선택하고 싶은 DOM 내부 property에 ref 객체를 설정
<input
	name="name"
    placeholder="이름"
    onChange={onChange}
    value={name}
    ref={nameInput} // 이 부분임
/>

// 4. DOM에 직접 접근
nameInput.current.focus();

nameInput.current 값은 현재 우리가 선택한 돔을 가리키게 된다. 따라서 이곳에 우리가 원하는 작업(focus 걸어주기)을 하면 되는 것이다.

 

 

아래는 전체 코드이다.

import React, { useState, useRef } from 'react';

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    nickname: '',
  });
  const nameInput = useRef();
  const { name, nickname } = inputs;

  const onChange = (e) => {
    const { name, value } = e.target;

    setInputs({
      ...inputs,
      [name]: value,
    });
  };
  const onReset = () => {
    setInputs({
      name: '',
      nickname: '',
    });
    nameInput.current.focus();
  };

  return (
    <div>
      <input
        name="name"
        placeholder="이름"
        onChange={onChange}
        value={name}
        ref={nameInput}
      />
      <input
        name="nickname"
        placeholder="닉네임"
        onChange={onChange}
        value={nickname}
      />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;

 

또한 useRef는 이런식으로 DOM을 선택하는 것 외에 렌더링과 전혀 관계없는 변수 같은 것들을 관리하게 될 때에도 사용할 수 있다. setTimeout, setInterval 을 사용할 때 주어지는 id 값, 외부라이브러리를 사용하여 생성된 인스턴스를 담을 때, Scroll 위치를 알아야 할 때 등의 경우를 예로 들 수 있다.

 

중요한 것은 useRef로 관리하는 값은, 그 값이 바뀌어도 컴포넌트가 리렌더링이 되지 않는다는 것이다.

 


 

const nextId = useRef(0);

const onCreate = () => {
	nextId.current += 1;
}

 

위와 같이 새로운 회원이 생성되었을 때 그 ID값useRef로 관리해줄 수 있다. 해당 값(회원의 ID값)이 바뀌어도 컴포넌트가 리렌더링이 될 필요가 없기 때문에, useRef로 관리해줄 수 있다.

물론 useState를 사용하여도 상관은 없다. 하지만 굳이 리렌더링이 돼야하는 값은 아니기 때문에, useRef를 활용하여 관리하는 것도 괜찮다는 것이다.

 

 

 

https://react.vlpt.us/ 강의자료를 참고하여 작성하였습니다.