Frontend/JavaScript

[useState/const] useState와 const의 관계

ayeongjin 2025. 4. 9. 18:29

🤔 useState는 const인데 왜 값이 변할까?

React를 사용할 때 가장 기본적으로 만나게 되는 훅이 useState이다.
아래와 같은 코드는 익숙하게 보이지만, 자바스크립트을 더 자세히 공부하면서 의문이 생겼다.

const [count, setCount] = useState(0);

분명히 const는 상수인데, 어떻게 count의 값이 계속 바뀔 수 있는 걸까?
이 글에서는 이 궁금증을 React 상태 관리의 흐름과 JavaScript의 const 개념을 중심으로 풀어봤다.
 
 


 

✅ let, const, var의 기본적인 차이

우선 자바스크립트에서 let, const, var의 차이를 간단히 정리해보면

  • var
    함수 스코프(function-scoped)이며, 호이스팅되고 중복 선언이 가능하다. 지금은 거의 쓰지 않는다.
  • let
    블록 스코프(block-scoped)이며, 재할당이 가능하다.
  • const
    블록 스코프(block-scoped)이며, 재할당이 불가능하다.

여기서 중요한 포인트는 const로 선언한 변수 자체를 재할당할 수 없다는 것이지,
변수 내부의 값(특히 객체나 배열 등 참조형 데이터)을 바꿀 수 없다는 의미는 아니다.
 


✅ useState의 역할

useState는 React에서 컴포넌트의 상태(state)를 관리하기 위해 사용하는 기본 훅(Hook)이다.
상태란 쉽게 말해 컴포넌트가 기억하고 있어야 할 값이다. 예를 들면 입력 값, 클릭 횟수, API 응답 등이다.

 
const [state, setState] = useState(initialValue);

이 구문은 useState 훅을 호출하면 다음 두 가지를 배열로 반환한다:

  1. state: 현재 상태 값
  2. setState: 상태 값을 업데이트하는 함수

React는 이 두 값을 배열 형태로 반환하고, 구조 분해 할당을 통해 const [count, setCount]처럼 받아올 수 있다.
 


✅ const인데 값이 변하는 이유

const는 변수 재할당을 금지하는 선언이므로 다음과 같은 코드는 에러를 발생시킨다.

const a = 1;
a = 2; // TypeError

 
하지만, useState를 통해 선언된 count는 값이 바뀌는 것처럼 보인다.
그 이유는 count라는 변수에 직접 값을 할당하는 것이 아니라,
React가 상태를 내부적으로 관리하고, 컴포넌트를 다시 실행하면서 새로운 값을 전달해주기 때문이다.

 

💡 실제로는 이런 구조

const [state, setState] = useState(initialValue);

이때 useState는 배열을 반환한다.
배열의 첫 번째 요소는 현재 상태 값이고, 두 번째 요소는 상태를 업데이트하는 함수다.
이 코드는 구조 분해 할당(destructuring assignment)을 통해 상태 값을 state에, 변경 함수를 setState에 담는다.
 
즉, 이 코드는 다음과 같은 의미다:

const result = useState(0); // 예: [0, function]
const count = result[0];
const setCount = result[1];
 

여기서 const는 배열을 구조 분해 할당한 변수 count와 setCount를 재할당하지 않겠다는 약속이다.
즉, count = 5처럼 직접 바꾸는 건 안 되지만,
setCount(5)는 React가 내부적으로 새로운 상태를 관리하는 것이므로 문제가 없다.

 

💡 상태 업데이트 흐름

실제로 상태 변경은 다음과 같은 흐름으로 일어난다.

[초기 렌더링]
      │
      ▼
const [count, setCount] = useState(0)
      │
      ▼
 count = 0

사용자가 setCount(1) 호출
      │
      ▼
 React 내부에서 상태 업데이트
      │
      ▼
 컴포넌트 다시 렌더링
      │
      ▼
const [count, setCount] = useState(1)
      │
      ▼
 count = 1

즉, setCount(1)은 count에 직접 값을 재할당하는 것이 아니라,
React에게 새로운 상태를 등록해달라고 요청하는 것이다.
 
React는 내부적으로 상태를 갱신하고 컴포넌트를 다시 실행하며,
count는 그 시점의 최신 상태 값을 받아온다.
 


 

✅ const 대신 let을 쓰면?

이론적으로 아래처럼 let으로 선언해도 동작에는 문제가 없다.

let [count, setCount] = useState(0);

 
 
하지만 이 경우 다음과 같은 실수를 유발할 수 있다.

count = 5; // ❌ 직접 재할당 → React 상태와 무관한 값

이는 React의 상태 추적 흐름과 충돌을 일으킬 수 있으며, 버그로 이어질 가능성이 크다.
따라서 직접 값을 바꾸지 않겠다는 의도를 명확히 하기 위해 const를 사용하는 것이 훨씬 더 안전하고 React스럽다고 한다.
 


✅ 요약 정리

  • const는 그 변수 자체를 재할당하지 않겠다는 의미일 뿐,
    내부 값이 변하지 않는다는 뜻은 아니다.
  • let도 가능은 하지만, 실수 위험이 크고 React의 상태 관리 철학과 맞지 않기 때문에 권장되지 않는다.
  • useState는 상태 값과 그 값을 업데이트하는 함수를 배열로 반환하고,
    그걸 const로 구조 분해 할당해서 참조만 유지하는 것이다.
  • setState를 호출하면 React가 상태를 업데이트하고 컴포넌트를 다시 렌더링하며,
    우리는 그 시점의 최신 상태 값을 const로 받는다.
  • 상태가 변하는 건 const로 선언한 변수 때문이 아니라,
    React 내부의 상태 관리 시스템 덕분이다.

 

✍️ 마무리

작은 궁금증에서 시작해 React의 내부 흐름을 이해하며, 상태 관리의 핵심 원리를 더 깊이 있게 체감할 수 있었다.
const는 변하지 않는 값이 아니라, React가 바꿔줄 값에 대해 내가 직접 건드리지 않겠다는 약속이다~!