🤔 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 훅을 호출하면 다음 두 가지를 배열로 반환한다:
- state: 현재 상태 값
- 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가 바꿔줄 값에 대해 내가 직접 건드리지 않겠다는 약속이다~!
'Frontend > JavaScript' 카테고리의 다른 글
[Map/Object] 자바스크립트의 Map과 Object (0) | 2025.05.04 |
---|---|
[JavaScript] Webpack (1) | 2025.02.02 |
[JavaScript] 자바스크립트의 클래스 (0) | 2025.01.27 |
[JavaScript] 자바스크립트의 변수 const, let, var (0) | 2025.01.26 |
[JavaScript] 호이스팅과 콜백함수 (0) | 2025.01.25 |