useRef에 대한 생각

Lee Jooam·2022년 5월 26일
0

언제 사용했을까

useRef는 은근히 많이 사용한다. 현재까지 내가 사용했던 것은 다음과 같다.

  1. 렌더링 된 DOM 요소에 접근할 때
    -> input에 focus하거나 value 값에 접근할 때 간편하다.
  2. 컴포넌트 내부에서 기억해야 할 가변 변수를 사용할 때
    -> 이 값이 변해도 리렌더링은 일어나지 않음

일반적으로 컴포넌트가 리렌더링 될 경우는 그 컴포넌트 함수가 다시 실행된다.

그 말은 내부에서 지역 변수를 선언해도 다시 초기화된다는 말이다.

이때 state를 통해 값을 변경하는 건 너무 과하다. 그 값을 기억할 때마다 리렌더링이 발생하기 때문이다.

값을 기억해야하지만 리렌더링은 원치 않을 때, 그때 ref 객체를 사용한다.

DOM에 접근하기

사실 ref를 가장 많이 사용하는 것은 렌더링 된 DOM 요소에 접근할 때일 것이다.

의문이 생긴다. 그냥 querySelector로 접근해도 되지 않나? 틀린 말은 아니다. 이미 렌더링된 요소라면 똑같이 접근해도 문제는 없다.

const App = () => {
  const [count, setCount] = useState(0);
  const inputRef = useRef();
  const inputDOM = document.querySelector("#myInput");

  console.log(inputRef);
  console.log(inputDOM);

  return (
    <>
      <div>{count}</div>
      <input type='text' id='myInput' ref={inputRef} />
      <button onClick={() => setCount((prev) => prev + 1)}>+</button>
    </>
  );
};

하지만 리액트의 이점을 생각해보면 이것은 비효율적인 접근이라고 생각된다. 리액트는 virtual DOM을 생성하고 그를 통해 자신의 상태를 비교, 업데이트한다.

virtual DOM과 실제 DOM을 동기화하는 작업, 이것이 리액트에서의 재조정이다. 리액트는 virtual DOM과 내부적인 로직을 통해 재조정 작업을 최적화한다.

virtual DOM은 그만큼 추가적인 메모리를 소모한다. 하지만 자바스크립트 객체인 virtual DOM에 접근하는 건 실제 DOM 요소를 순회하는 것보다 빠르다.

그렇기 때문에 리액트 내부에서 관리하는 ref 객체에 접근하는 게 querySelector로 DOM을 참조하는 것보다 빠른 것이다.

비용에 맞는 확실한 이점이 있는 것이다.

그리고 위의 코드에서 또다른 문제가 있다.

const App = () => {
  const [count, setCount] = useState(0);
  const inputRef = useRef();
  const inputDOM = document.querySelector("#myInput");

  const handleClick = () => {
    console.log(inputRef.current.value);
    console.log(inputDOM);
  };

  console.log(inputRef);
  console.log(inputDOM);

  return (
    <>
      <div>{count}</div>
      <input type='text' id='myInput' ref={inputRef} />
      <button onClick={() => setCount((prev) => prev + 1)}>+</button>
      <button onClick={handleClick}>CLick</button>
    </>
  );
};

다음과 같은 코드를 실행시켜 보면 답이 나온다. inputDOM은 렌더링 되기 이전에 선언되었기 때문에 null 값을 참조한다.

하지만 ref는 리액트 element가 렌더링되고 난 후 연결된다.

이미 존재하는 것을 querySelector로 고르든 렌더링 되기 이전에 querySelector로 고르든 문제인 것이다.

후기

DOM에 접근하는 것은 일반적인 자바스크립트 객체에 접근하는 것보다 보통 느리다. 리액트는 그런 DOM 요소들을 자바스크립트 객체에 저장하고 추상화한다.

synthetic event도 리액트가 추상화하는 것 중 하나이다.

DOM 업데이트, 접근, 이벤트 등 리액트의 이점을 잘 이용하자.

profile
프론트엔드 개발자로 걸어가는 중입니다.

0개의 댓글