이 글에서는 React 상태(state)와 참조(refs)의 차이점을 면밀히 비교하고, 특정 시나리오에서의 적합성을 탐구할 것입니다.

React 애플리케이션에서 데이터를 저장해야 할 때 마음에 떠오르는 첫 번째 질문은 “컴포넌트의 생명주기 동안 언젠가 데이터가 변경될까요?”입니다. 만약 변경되지 않는다면, 일반 const 변수가 적합합니다.

그러나 데이터가 변경된다면, 그때 useStateuseRef 훅이 사용됩니다.

useStateuseRef 훅 이해하기

useState

useState 훅은 컴포넌트의 상태를 관리하기 위해 설계되었으며, 시간이 지남에 따라 변경될 수 있는 데이터를 나타내고 컴포넌트의 렌더링에 중요합니다. React에서 useState 훅을 가져와 컴포넌트에 상태를 추가할 수 있습니다.

import { useState } from 'react';

useState 훅은 보통 초기값으로 초기화되며 선언된 상태 변수와 그와 연관된 설정 함수의 배열을 반환합니다. 다음과 같습니다:

import { useState } from "react";

function App() {
  const [count, setCount] = useState(0); // useState 훅 선언

  return (
    <>
      <h1>상태 예제</h1>
      <div>
        <button onClick={() => setCount((count) => count + 1)}>
          count is {count}
        </button>
      </div>
    </>
  );
}
export default App;

위 코드에서,

  • useState는 0의 값으로 초기화되고 count 변수와 setCount 설정 함수를 반환합니다.
  • 버튼을 클릭할 때마다 App 컴포넌트가 다시 렌더링되고 버튼 텍스트 내에 업데이트된 값이 표시됩니다.

React 상태를 잘 이해하는 것은 가장 많이 사용되는 개념 중 하나이기 때문에 중요합니다.

useRef

useRef 훅은 React 컴포넌트에서 참조를 생성하는 데 사용됩니다. 참조는 값이 들어 있는 current 속성을 가진 객체입니다. 기본적으로 DOM 요소나 컴포넌트의 인스턴스를 참조합니다. current 속성에 접근하여 값을 읽고 업데이트할 수 있습니다.

const ref = useRef(initialValue)

ref.current = initialValue

다음은 ref를 사용한 전체 코드 스니펫입니다:

import { useRef } from "react";

function App() {
  let ref = useRef(0); 

  function handleIncrease() {
    ref.current++;
    alert(`You have clicked it ${ref.current} times`);
  }
  return (
    <>
      <h1>Ref 예제</h1>
      <div>
        <button onClick={handleIncrease}>Click Me</button>
      </div>
    </>
  );
}

export default App;

자세히 살펴보면:

  • React에서 useRef를 가져왔습니다.
  • App 컴포넌트에서 초기값이 0인 참조 객체를 선언했습니다.
  • handleIncreaseref.current 값을 1 증가시키고 현재 값에 관한 사용자의 경고 역할을 합니다.
  • App 컴포넌트의 JSX에서는 onClick 속성을 가진 버튼과 handleIncrease 핸들러 함수를 전달받습니다.

두 훅이 어떻게 작동하는지 이해했으므로, 적합한 사용 사례를 탐색하고 비교할 것입니다.

React 상태 vs Ref

렌더 트리거

React에서는 상태 변경이 항상 재렌더링을 유발합니다. 이는 조정(재조정)이라는 메커니즘을 통해 이루어지며, 상태나 속성의 변경에 기반하여 사용자 인터페이스를 업데이트합니다.

반면, 참조에 변경이 발생해도 재렌더링을 유발하지 않습니다. 참조는 컴포넌트의 렌더링 주기와 직접 연결되어 있지 않습니다.

따라서, 데이터 변경에 반응하는 일관된 사용자 인터페이스를 원한다면 상태 사용이 권장됩니다. 참조는 사용자 인터페이스에 영향을 주지 않고 가변 값을 관리하는 데 더 적합합니다.

변경 가능성

React 상태는 설정 함수 업데이트를 통해 한 번 설정되면 직접 변경할 수 없습니다. 이 방식을 사용함으로써 React는 데이터 흐름의 예측 가능성과 안정성을 유지합니다. 이는 디버깅을 더 쉽게 만듭니다.

반면, 참조는 렌더링 과정 외부에서 ref 현재 값을 수정할 수 있어 변경 가능합니다. 상태와 달리 참조는 업데이터 함수가 없습니다.

읽기/쓰기 작업

useState 훅 설정 함수를 사용하여 상태 값을 업데이트할 수 있습니다. 예를 들어:

const [state, setState] = useState(false)
function handleOpposite(){
    setState(!state)
 }

이 코드에서 볼 수 있듯이:

  • 초기값은 false인 불리언 값으로 설정됩니다.
  • handleOpposite 함수는 상태의 불리언 값을 부정하고 setState에 업데이트된 참 값이 저장됩니다.

이 간단한 작업에서,

  • 초기값에 접근하기 전에 암시적인 읽기 작업이 수행되었습니다.
  • 초기값에 부정(!)을 사용하여 값을 반대로 변경했을 때 쓰기 작업이 발생했습니다.

한편, 렌더링 중에 참조의 current 값을 액세스하거나 수정하면 React의 조정 과정을 방해하고 가상 DOM과 실제 DOM 간의 일관성에 문제를 일으킬 수 있습니다.

컴포넌트의 예측 가능한 동작과 최적의 성능을 보장하기 위해서는 React의 지침을 준수하고 렌더링 중에 참조를 액세스하거나 수정하는 것을 피하는 것이 최선입니다.

렌더 간 지속

렌더 간 데이터 지속은 React에서 데이터가 다른 렌더 주기의 컴포넌트 간에 일관되고 사용 가능한 상태로 유지됨을 의미합니다. 데이터가 지속될 때 재렌더링 후에도 변경되지 않고 접근 가능합니다. 상태와 참조 모두 렌더 간에 데이터를 지속시킵니다.

비동기 업데이트

React 상태 업데이트는 비동기적이므로, 업데이트 요청 시 즉시 실행되지 않을 수 있습니다. React는 다른 컴포넌트를 한 번에 업데이트하는 동안 일부 상태 변경을 나중으로 미룰 수 있습니다!

참조 업데이트는 동기적으로 수행되며, 각 작업은 이전 작업이 완료될 때까지 대기한 후 순차적으로 실행되어 예측 가능하고 결정적인 방식으로 실행됩니다.

결론

이 글에서는 React 애플리케이션에서 변경될 데이터를 처리하는 훅 — useStateuseRef — 에 대해 광범위하게 살펴보았습니다.

두 훅을 비교해 보았으며 이제 그들의 유사점, 차이점, 언제 어디서 가장 적합한지 알게 되었을 것입니다.