[7주차] useState VS useRef

voyager 999·2024년 2월 1일

React

목록 보기
13/27
post-thumbnail

리액트의 useState와 useRef

useState
처음 리액트를 배우며 접했을 때는 낯설기만 했는데 이제 퍽 익숙해진 개념이다. 리액트가 제공하는 Hooks 중 하나로, 리액트 프로젝트 내에서 변화하는 값인 State를 관리할 수 있는 기능이다. setState에 의해 state가 변화하면 변경된 내용을 표시하기 위해 리렌더링이 일어난다.

useRef
역시 리액트의 기본 Hook으로, 이걸 사용해서 공간(변수)을 만들어 두고, 거기에 특정 DOM 요소나 값을 저장해 두고 나중에 사용할 수 있다. 즉, 콕 찝어서 접근하고 싶은 요소를 따로 저장해두고 필요할 때 참조 및 활용할 수 있는 기능이다. 이 공간에 저장된 값은 변화하더라도 리렌더링이 일어나지 않는다. 따라서 사용자에게 시각적으로 보여질 필요가 없지만 기능 구현을 하는 데에 있어 추적이 필요한 값이 있다면 useRef를 이용해 볼 수 있다.


코드로 비교해보기

useState와 useRef의 차이점을 비교해 볼 수 있는 간단한 코드를 작성해 보았다.


import { useState, useRef } from "react";
import "./App.css";

function App() {
  const [inputValue, setInputValue] = useState(0);
  const inputRef = useRef();

  const checkUseStateValue = (e) => {
    setInputValue(e.target.value);
    console.log(`useState에 입력된 값 ${inputValue}`);
  };

  const checkUseRefValue = () => {
    console.log(`useRef에 입력된 값 ${inputRef.current.value}`);
  };

  return (
    <>
      <div className="diiv">
        <h1>💚useState</h1>
        input에 값을 입력할 때마다 setInputValue 되고,
        <br />
        입력된 값이 바로 화면에 렌더링된다.
        <br />
        <input type="text" value={inputValue} onChange={checkUseStateValue} />
        <br />
        입력값 확인: {inputValue}
      </div>
      <div className="diiv">
        <h1>💚useRef</h1>
        input에 값을 입력해도 렌더링되지 않지만,
        <br />
        console에서는 입력과 동시에 값이 확인이 되고 있다.
        <br />
        useState 칸이 입력될 때 비로소 아래에 최종값이 출력된다. <br />
        <input type="text" ref={inputRef} onChange={checkUseRefValue} />
        <br />
        입력값 확인 : {inputRef.current && inputRef.current.value}
      </div>
    </>
  );
}

export default App;

useState와 useRef의 공통점

두 개의 Hook 모두 사용자가 input에 입력하는 값을 저장하고 그 변화를 추적한다. 이 값을 다른 곳에서 참조하여 활용할 수 있다.

빈칸에 입력되는 값이 감지되어 console창에서 확인 가능하고, 나중에 이 값을 다른 곳에서 참조하여 사용할 수 있다.

useState와 useRef의 차이점

  1. 값의 변화에 따른 렌더링 여부 :
    우선 바로 위에 보이는 스크린샷에서처럼, useState의 경우 inputValue를 참조했을 때 input에 값이 입력될 때마다 setState되면서 화면에 리렌더링('입력값 확인' 부분)이 일어나지만, useRef의 경우 input에 값이 입력되어도 화면에 바로 나타나지 않는다. console에서는 값의 변화가 계속 감지되고 있지만, 렌더링이 일어나지 않는다.
    useState input에 한번 더 입력을 하면 setState에 의해 리렌더링이 일어나므로 이 때 useRef의 변화된 값도 함께 렌더링된다.

  2. 초깃값 설정 여부 :
    useState는 초깃값이 비어있다 하더라도 최소한 데이터유형을 나타낼 수 있는 초깃값 설정이 필수적이었다. 하지만 useRef을 사용할 때는 초깃값 설정을 하지 않는다. useRef 역시 선언 단계에서 초깃값을 설정할 수는 있다. 하지만 useRef의 주요 사용 목적은 상태값 관리가 아니라 DOM 요소에 대한 참조를 생성하는 데에 있으므로, 상태값을 초기화하면 useRef의 주된 용도를 벗어나는 게 된다.

  3. 그래서 일어나게 되는 출력 템포 차이
    따라서, 2개의 input에 동일하게 12345를 입력했을 때, console에 찍히는 결과에 차이가 생긴다. useRef는 사용자가 입력하는 템포와 입력값의 출력 템포가 동일하지만, useState는 한박자씩 늦게 따라오게 된다.
    setState함수는 비동기적으로 동작하여, console.log에서 현재의 입력값을 찍을 때, inputValue가 업데이트 되기도 전에 출력이 되어 버리기 때문이다. console.log에서 실제로 업데이트된 값을 확인하려면 useEffect를 사용하여 의존성배열에 inputValue를 넣어주면 된다.

  4. {inputValue}와 {inputRef}가 담고 있는 내용의 차이
    setState input의 value인 {inputValue}는 input에 사용자가 입력한 값이 들어가기 때문에 {inputValue}로 바로 값에 접근할 수 있었다.
    하지만, inputRef는 { current: ... } 형태의 객체이다.
    {input.current}는 바로 현재 참조하고 있는 DOM 엘리먼트, 즉 이 경우 HTML의 input태그를 가리키게 된다. 따라서 내가 사용하고자 하는 '입력값'은 {inputRef.current.value}와 같이 접근해야 한다.


console.log{inputRef}; // [object object]
console.log{inputRef.current}; // [object HTMLInputElement]
console.log{inputRef.current.value}; //input에 입력한 값 출력

이 inputRef.current가 존재하고, 그 값이 truthy한 경우에만 출력할 수 있어야 하므로, 최종적으로 useRef의 input 입력값에 접근하기 위한 코드는 {inputRef.current && inputRef.current.value}가 되어야 한다.

시사점

useState와 useRef는 비슷한 듯 하지만 서로 다른 점도 많이 있었다. 따라서 각각 적절한 상황에서 사용할 수 있어야 하겠다고 느꼈다.

  • useState는 컴포넌트 내에서 state를 변경하고 그에 따른 리렌더링이 필요한 경우에 사용한다.
  • useRef는 렌더링과 무관한 값을 참조할 때 사용한다. 또한 이 ref에 저장된 값과 새로 들어온 값을 비교할 때 사용할 수 도 있겠다.
  • 아직은 구체적으로 어떤 경우에 useRef를 십분 활용할 수 있을지 크게 감은 오지 않지만, 두 개념의 차이점은 확실히 알게 된 것 같다.

0개의 댓글