Hook(3): useRef

Hyun·2021년 9월 20일
0

리액트 훅

목록 보기
3/14

useRef로 DOM노드나 React 엘리먼트에 접근하기

자바스크립트에서 특정 DOM을 선택해야할 때는 DOM Selector를 사용한다. 리액트에서도 특정 요소의 크기를 가져온다거나, 포커스를 설정해야 한다거나 특정 DOM을 선택해야 할 상황이 있다.

이런 경우, 리액트 함수형 컴포넌트에서는 react hook 중 하나인 useRef함수를 사용한다.
클래스형 컴포넌트에서는 콜백함수를 사용하거나 React.createRef함수를 사용한다.

사용법

  • 먼저 Ref객체를 만들어준다.
const element = useRef();
  • 선택하고 싶은 DOM에 속성으로 ref값을 설정해준다.
<input onChange={onChange} value={text} ref={element} />
  • Ref객체의 current값은 우리가 선택한 DOM을 가리킨다. 따라서 current값에 사용하고 싶은 DOM API를 호출한다.
    (DOM API: Javascript에서 HTML을 제어하는 여러가지 명령들)
element.current.focus();

사용 예제

초기화 버튼을 누르면 input태그에 있는 값이 초기화되고 focus가 잡히는 기능을 구현하였다.

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

const useRefPrac = (initialText) => {
  const [text, setText] = useState(initialText);
  const element = useRef();
  
  const onChange = (e) => {
    const {target:{value}} = e;
    setText(value);
  }

  const onReset = (e) => {
    e.preventDefault();
    setText('');
    element.current.focus();
  }

  return {text,element, onReset, onChange};
}
 
const App = () => {
  const {text, element, onReset, onChange} = useRefPrac("text를 입력하세요");
  return(
    <div className="App">
      <input onChange={onChange} ref={element} value={text}/>
      <button onClick={onReset}>초기화</button>
    </div>
  )
}

export default App;

before

after

useRef로 컴포넌트 안의 변수 관리하기

useRef hook은 DOM 선택 용도 외에도, 컴포넌트 안에서 조회 및 수정 가능한 변수를 관리하는 용도가 있다. useRef로 변수를 관리하게 되면, 변수가 업데이트 될 때 컴포넌트가 리렌더링 되지 않고, 컴포넌트가 렌더링 될 때 변수의 값이 초기화 되지도 않는다. 따라서 useRef 로 정의된 변수는 항상 stable 한 상태를 유지할 수 있으며, 결과적으로 변수를 참조하는 함수는 실행될때마다 항상 현재(최신)의 값을 참조할 수 있다.

useRef를 활용한 변수는 아래와 같은 곳에 쓰인다.

  • setTimeout, setInterval을 통해 만들어진 id
  • scroll 위치
  • 배열에 새 항목을 추가할 때 필요한 고유값 key

예시

import React, {useState, useEffect, useRef} from 'react';
import UserList from "./UserList";

function App(){
  const users = [
    { id:1, username: 'henry', email: 'henry@email.com' },
    { id:2, username: 'malia', email: 'maliay@email.com' },
    { id:3, username: 'tomson', email: 'tomsony@email.com'}
  ];

  const nextId = useRef(4);
  const onCreate = () => {

    //배열에 새로운 항목 추가하는 로직 생략

    nextId.current += 1;
  };
  return <UserList users={users}/>;
}

export default App;

useRef()함수를 이용해 고유값 변수로 nextId를 설정해주고 인자로 id가 될 숫자 4를 넣어준다.
따라서 인자로 넣어준 값이 변수의 current값이 된다. nextId변수를 수정하거나 조회하려면 .current값을 수정하거나 조회한다.

추가 예시: useCallback 에서 사용되는 useRef 변수

useRef로 setInterval, setTimeout 함수 clear하기

setInterval이나 setTimeout과 같은 함수는 clear시켜주지 않으면 메모리를 많이 소모한다. 따라서 함수를 구현하고 컴포넌트가 unmount될때나 특정 상황에서 clear해줄 필요가 있다.

예시

function Timer() {
  const intervalRef = useRef();

  useEffect(() => {
    const id = setInterval(() => {
      // ...
    });
    intervalRef.current = id;
    return () => {
      clearInterval(intervalRef.current);
      //컴포넌트가 unmount될때 clearInterval을 활용해서 
      //setInterval함수가 들어있는 ref객체를 초기화해준다.
    };
  });

  // ...

interval이나 timeout을 설정할때는 ref가 필요하지 않지만, 설정된 것을 지울 때 유용하다.

주의사항

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

[출처 및 참고]
ko.reactjs
xiubindev.tistory
DaleSeo/react-refs

profile
better than yesterday

0개의 댓글