티스토리 뷰

React state 선언 과정에서는 왜 const를 쓸까?

최근 JavaScript를 이용하여 알고리즘 문제를 풀이하다 궁금증이 들게 되었다.

React - useState

 

React 공식문서에서 볼 수 있듯, 우리는 당연하게 const를 이용한 상태 관리 hook useState를 사용하고 있었던 것이다.

왜 우리는 const로 사용해야 하고, React에서는 어떻게 동작하는지 알아보도록 하자.

 


1. React의 상태 관리 원리

JavaScript에서는 데이터 타입을 다음과 같이 분류한다.

  1. Primitive Data Types (원시 타입)
    • undefined
    • Boolean
    • Number
    • String
    • BigInt
    • Symbol
  2. Structural Data Types (참조 타입)
    • Object
    • Functions
    • Array
    • Map

변수를 통해 값을 재할당하는 경우, immutable한 타입은 value 값 자체를 전달하기 때문에, 기존의 데이터와 독립된 형태로 사용이 가능하다.

 

mutable한 타입의 경우, reference 를 전달하여 같은 메모리 주소를 공유한다.

 

즉, mutable value는 값의 메모리 주소를 참조하여 사용하는 방식이기 때문에, 값을 변경하는 경우 해당 값을 사용하는 모든 곳에 영향을 주게 된다. → Side Effect(부수 효과)가 발생하게 되는 것이다.

 

이러한 문제들을 해결하기 위해서는 약간의 비용을 조금 더 들이지만 객체를 불변 객체 형태로 사용하는 것이다.

 

React에서는 이러한 이유로 useState는 상태 값을 불변으로 유지하면서 새로운 상태 값을 생성하여 React 컴포넌트가 이를 감지하고 다시 렌더링하도록 설계되어 있다.

 

 

즉, 상태 변경은 항상 React의 내부 메커니즘을 통해 이루어지며, state 변수 자체를 직접 변경하지 않는 구조라고 볼 수 있다.

 

여기서 중요한 점은 state 변수 자체를 직접 변경하지 않는다는 것!

 

 


2. const, var, let의 차이

그렇다면 왜 const를 사용했을까?

var, let, const는 JavaScript에서 변수를 선언할 때 사용하며, 서로 다른 동작 방식과 스코프 규칙을 가지고 있다.

 

 

1. 선언 및 재할당 가능 여부

키워드 재선언 가능 여부 재할당 가능 여부
var 가능 가능
let 불가능 가능
const 불가능 불가능

 

  • var: 같은 이름의 변수를 다시 선언할 수 있다.
  • var x = 10; var x = 20; // 재선언 가능 console.log(x); // 20
  • let: 같은 이름으로 변수를 다시 선언할 수 없다. 하지만 값의 재할당은 가능.
  • let y = 10; // let y = 20; // SyntaxError: Identifier 'y' has already been declared y = 20; // 재할당 가능 console.log(y); // 20
  • const: 선언 이후 값을 변경하거나 재선언할 수 없다.
  • const z = 10; // z = 20; // TypeError: Assignment to constant variable // const z = 30; // SyntaxError: Identifier 'z' has already been declared console.log(z); // 10

 

2. 스코프(Scope)

키워드 스코프 종류 스코프 특징
var 함수 스코프 블록 내부에서 선언해도 함수 바깥에서 접근 가능
let 블록 스코프 블록 내부에서만 접근 가능
const 블록 스코프 블록 내부에서만 접근 가능
  • var의 함수 스코프
      if (true) {
        var x = 10;
      }
      console.log(x); // 10 (블록 스코프를 무시)
  • var로 선언된 변수는 블록({ })을 무시하고 함수 내부 어디서든 접근할 수 있다.
  • letconst의 블록 스코프
      if (true) {
        let y = 20;
        const z = 30;
      }
      // console.log(y); // ReferenceError: y is not defined
      // console.log(z); // ReferenceError: z is not defined
  • letconst는 블록({ }) 내부에서만 유효하다.

 

3. 변수 호이스팅(Variable Hoisting)

키워드 호이스팅 여부 초기화 시점
var 호이스팅 됨 undefined로 초기화
let 호이스팅 됨 초기화 전 접근 시 에러
const 호이스팅 됨 초기화 전 접근 시 에러

 

호이스팅이란?

변수 선언이 코드의 맨 위로 끌어올려지는 현상을 말한다.

 

 

이 때, var과 let, const 간에 초기화 과정에 차이가 존재한다.

  • var는 호이스팅 후 초기화가 undefined로 됨.
  • console.log(a); // undefined var a = 10;
  • letconst는 호이스팅 되지만, 초기화되기 전 접근하면 에러 발생.
  • console.log(b); // ReferenceError: Cannot access 'b' before initialization let b = 20;

 

4. 기본적인 사용 권장 사항

  1. var는 사용을 지양해야 함: 함수 스코프와 호이스팅 특성으로 인해 의도치 않은 버그가 발생할 가능성이 높음.
  2. let은 값의 변경이 필요한 경우 사용: 재할당이 필요한 변수에 적합.
  3. const는 값의 변경이 없는 경우 사용: 상수 선언이나 값 변경을 방지하고 싶을 때 사용.

 

 


3. const로 state를 관리하는 내부 사정

const로 선언된 변수는 참조 자체가 변하지 않는다.

(물론 참조하는 값인 객체나 배열과 같은 요소는 내부적으로 변경이 이뤄질 수 있지만..!)

React의 상태에서 const를 사용하는 이유는 크게 아래 두 가지로 볼 수 있다.

 

1. 상태의 참조를 고정하기 위해

React는 useState로 반환된 statesetState를 특정 컴포넌트의 상태 관리와 연결한다. 이 연결을 깨지 않기 위해 상태 변수(state)를 재할당하지 않는 것이 중요한 것.

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

// 잘못된 예: 상태 참조를 재할당 (의도한 동작이 깨질 수 있음)
count = 5; // TypeError: Assignment to constant variable

2. 의도하지 않은 상태 변경 방지

const를 사용하면 상태 참조를 재할당할 수 없으므로 실수로 state를 직접 변경하는 상황을 방지할 수 있다. 대신 setState를 사용하도록 유도하여 React의 올바른 상태 관리 규칙을 따르게 하는 것이다.


3. let 또는 var를 사용할 수 없음

let이나 var는 동일한 변수에 대해 재할당이 가능하므로 상태 관리 로직을 혼란스럽게 만들 수 있다. 예를 들어, 아래와 같이 상태를 직접 변경하거나 참조를 재할당하면 React의 상태 관리 시스템이 이를 감지하지 못하게 된다.

 

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

// 잘못된 예: 상태를 직접 변경 (React는 이를 감지하지 못함)
count = 5;

// 올바른 예: 상태를 변경하려면 반드시 setState를 사용
setCount(5);

 

React에서는 상태가 변경되면 렌더링 트리새롭게 생성한다. 만약 immutable하게 데이터를 변경하지 않는다면, 새로운 객체가 생성되지 않고, 메모리 주소에 있는 데이터만 변경되기 때문에, React에서는 상태의 변경을 감지할 수 없게 된다.

마무리

 

오늘은 그동안 가볍게 넘어갈 수 있었던 내용에 대해 알아보았다.

단순히 이렇게 사용하는구나라고 생각하고 넘어가기에는 기본적인 구조 자체를 이해하도록 도움을 주는 근본적인 개념이다보니, 변수와 상태를 작성하는 과정에서도 많은 것을 고려하며 작성해야 한다는 것을 깨닫게 했다.

 

이번 변수 스코프에 작성한 김에 다음 포스팅에서는 스코프에 대해 톺아보고, 클로저에 개념에 대해 알아보도록 해봐야겠다.

참고 자료


https://velog.io/@wha1eson/Mutation%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-Mutable-vs-Immutable

https://ko.react.dev/reference/react/useState

https://dudghsx.tistory.com/entry/hooks%EC%97%90%EC%84%9C-useState%EA%B0%80-const%EB%A1%9C-%EC%84%A0%EC%96%B8%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0

'Front-End' 카테고리의 다른 글

[TypeScript] 제네릭(Generic)이란 무엇인가?  (1) 2025.01.02
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함