프론트엔드/React.js

[React] ref와 useRef 사용법을 알아보자

earthssu 2022. 4. 13. 10:57

최근 졸업 프로젝트를 시작하면서 다시 리액트를 공부해야 하는 상황이 생겼다.

이 프로젝트 내에서 ref를 유용하게 쓸 수 있을 것 같아 공부 겸 다시 정리해보려고 한다.

 

개념은 책 '리액트를 다루는 기술'을 참고했다.

 

 

ref ?

일반적으로 HTML에서 DOM 요소에 이름을 달 때는 id를 사용한다. 그래서 CSS에서 특정 id에 스타일을 적용하거나 Javascript에서 특정 id에 접근해 작업할 수 있는 것이다.

이렇게 HTML에서 id를 사용해 DOM에 이름을 다는 것처럼 리액트 프로젝트 내부에서 DOM에 이름을 다는 방법 ref라고 한다.

 

어라 잠깐, 리액트 프로젝트에서는 id를 쓸 수 없는 건가?

쓸 수 있다! 그러나 리액트는 컴포넌트 단위로 이루어지는데, 컴포넌트가 여러 번 사용될 경우 '유일성'을 보장해야 하는 id가 여러 개 생기게 되어 문제가 발생한다. 대신 ref는 전역적으로 작동하지 않고 컴포넌트 내부에서만 작동하기 때문에 유일성에 대한 문제가 발생하지 않는다.

 

 

이러한 ref를 대체 어디에 써야 잘 썼다고 소문이 날까? 바로 DOM을 직접 건드려야 할 때이다.

jQuery에서는 input값을 검사할 때 특정 id를 가진 input에 class를 설정하여 스타일을 바꿔준다. 이러한 작업은 리액트에서 state를 이용해 구현할 수 있다. 그러나 state 만으로 해결할 수 없는 상황이 발생한다. 바로 아래와 같은 상황들이다.

 

특정 input에 포커스 주기

스크롤 박스 조작하기

Canvas 요소에 그림 그리기

 

이러한 상황에서는 DOM에 직접적으로 접근해야 하는데, 이를 위해서 ref를 사용한다.

 

 

리액트에 Hook 개념이 등장하기 전까진 ref를 클래스형 컴포넌트에서만 사용할 수 있었다. 그러나 Hook의 useRef 함수가 등장하면서 함수형 컴포넌트에서도 ref를 사용할 수 있다. 개인적으로 함수형 컴포넌트를 훨씬 많이 사용하기 때문에 (일반적으로도) 이  useRef 함수 사용법 중심으로 ref의 사용 방법을 소개하도록 하겠다.

 

 

useRef

함수형 컴포넌트에서 ref 쉽게 사용할 수 있도록 해주는 Hook이다.

const inputEl = useRef(null);

const onInsert = useCallback(() => {
  const nextList = list.concat(parseInt(number));
  setList(nextList);
  setNumber("");
  inputEl.current.focus();
}, [number, list]);

<input value={number} onChange={onChange} ref={inputEl}></input>

useRef를 통해 ref를 정의해주고, 접근하고 싶은 element에 해당 ref를 할당해준다.

위의 코드를 실행하면 onInsert 함수가 실행되었을 때 input 박스로 포커스가 이동되는 것을 확인할 수 있다.

 

컴포넌트 로컬 변수를 사용해야 할 때도 useRef를 사용할 수 있다. 여기서 로컬 변수란 렌더링과 상관없이 바뀔 수 있는 값을 말한다. 그래서 ref 값이 바뀌어도 useEffect 같은 함수를 실행할 때와 달리 컴포넌트가 렌더링되지 않는다는 점에 주의한다. 렌더링과 관련되지 않은 값을 사용할 때만 이와 같은 기술을 사용하도록 한다.

 

 

매번 접할 때마다 새로운 Hook 그리고 ref......

오늘 정리한 개념을 바탕으로 프로젝트가 성공적으로 진행되길 기원해본다......