[React] useState VS useRef

꾸개·2024년 1월 16일
0
post-thumbnail
post-custom-banner

개요

리액트를 처음 시작할 때 가장 먼저 배우는 훅은 useState였다. 상태를 변수처럼 선언하고 상태를 변경하면서 변경된 값으로 컴포넌츠를 렌더링하는 과정이 신기하게 느껴졌다. 특히, 사용법이 크게 어렵지 않았는데 state로 상태를 선언하고 setState로 변경할 상태를 인자로 넣어주면 끝이었다.

그 다음에 배운것이 useRef였다. useRef는 HTML DOM을 참조하여 해당 요소 속성을 변경할 때 주로 사용했었다. null로 초기화를 시켜놓고 원하는 요소에 ref 속성으로 해당 요소를 참조하여 속성을 확인할 수 있었다.

기술면접 리스트를 확인하면서 공부하던 와중에 한 가지 질문이 눈에 띄었다.

useState와 useRef의 차이점을 설명하시오

?? 둘은 아예 다른훅이 아니었던가? 너무나 당황스러웠다. 그 동안 공부를 잘 못하고 있던 것 같았다. 하지만, 진짜 면접보기 전에 확인한게 어디인가? 그래서 이번엔 내가 어떠한 부분을 간과하고 있었고 또 어떠한 차이점이 있는지 알아보고 정리해볼 것이다.


useState

useState는 컴포넌트에 state 변수를 추가할 수 있게 해주는 React 훅입니다.

내 말은 틀리지는 않았다. 그런데 조금 더 디테일하게 살펴보면서 한가지 키워드가 눈에 띄었다.

state를 다른 값으로 업데이트하고 리렌더링을 촉발할 수 있는 set(설정자) 함수입니다.

set함수에서 내가 간과하고 있던 부분이 눈에 띄었다. 리렌더링을 촉발할 수 있는 함수라는것이다.

Virtual DOM이 해당 상태변화를 감지하고 다시 렌더링하는 점에서 리렌더링이 발생하는데, 이것으로 그동안 화면에 요소값을 바꿀 수 있었다.

import React, { useState } from 'react';

export function App(props) {

  const [value, setValue] = useState('');
  console.log("리렌더링 발생");

  return (
    <div className='App'>
      <h1>input을 입력하세요</h1>
      <input onChange={e => setValue(e.target.value)}></input>
      <h2>{value}</h2>
    </div>
  );
}

input이 change이벤트를 일으킬때마다 set함수를 실행시켜 상태를 변화시키고 변화된 값은 재렌더링을 통해 h2의 값으로 저장되어 화면에 나타난다.

의도했던 완벽한 기능이지만, 문제가 있다. change이벤트 즉, 내가 input의 값을 완성시켰을때가 아니라 변화시킬때마다 재렌더링을 촉발한다는 점이다.

콘솔을 살펴보면 input 값이 변화할때마다 렌더링된다는것을 알 수 있다. 물론 해당 입력하는값이 바뀔때마다 화면에 재렌더링 하고 싶다면 상관없을 수 있지만,

  1. 완성된 값만 렌더링 시키고 싶다면?
  2. 완성된 값을 얻어야하는 컴포넌츠가 많다면?
  3. 100개의 컴포넌츠가 동시에 리렌더링 된다면?
  4. 100개의 상태가 동시에 set함수를 호출한다면?

이러한 케이스들을 생각해보면 useState 훅은 좋은 방안이 아닐수도 있다는 생각이 들었다.


useRef

useRef는 그냥 DOM을 참조하는거 아니야? 했던 생각을 바꾸는 문장이 있었는데,

useRef() Hook은 DOM ref만을 위한 것이 아닙니다. “ref” 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너입니다. 이는 class의 인스턴스 프로퍼티와 유사합니다. 만약 ref={myRef}를 사용하여 React로 ref 객체를 전달한다면, React는 모드가 변경될 때마다 변경된 DOM 노드에 그것의 .current 프로퍼티를 설정할 것입니다. useRef는 내용이 변경될 때 그것을 알려주지는 않는다는 것을 유념하세요. .current 프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않습니다.

DOM을 참조한다기보다는 어떤 값이든 보유할 수 있는 일반 컨테이너로 개념을 바꿔보자. 그렇다면 useState로 저장한 값을 잠깐 ref에 저장했다가 원할때만 재렌더링 시키면 되지 않을까? 라는생각이 들었다.

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

export function App(props) {
  const myRef = useRef(null);
  const [value, setValue] = useState("")

  console.log("리렌더링 발생");

  const valueHandler = () => {
    const { current } = myRef;
    console.log(current)
    setValue(current.value);
  }

  return (
    <div className='App'>
      <h1>input을 입력하세요</h1>
      <input ref={myRef}></input>
      <h2>{value}</h2>
      <button onClick={valueHandler}>제출</button>
    </div>
  );
}

onChange를 삭제하고 useRefinput을 참조해준다. 그리고 stateset함수를 버튼을 클릭할때 동작하게 만들어준다. 이렇게 되면, myRefinput 값을 갖고있고, 버튼을 누를경우 set함수로 기존 상태를 current.value 로 바꾸어준다.
이렇게 되면 첫번째 렌더링에서 콘솔이 찍히고 버튼을 눌러 set함수를 실행 시켰을 때 리렌더링이 한번 총 2번의 렌더링이 발생한다.


결론

useRef를 써야 정답이 아니라 상황에 맞게 써야하는 것 같다. 말했듯이, 입력도중의 값을 원하거나 입력도중에 화면이 바뀌어야 할 경우에는 useState가 맞지만, 종료된 시점의 값을 원한다면 useRef로 리렌더링을 방지하면서 최적화를 할 수 있다.


참고: https://velog.io/@skawnkk/useState-vs-useRef

profile
내 꿈은 프론트 왕
post-custom-banner

0개의 댓글