Front-end/React

[React] React의 불변성

NaDuck 2023. 11. 12. 19:37

 

목차

1. 불변성이란?

2. React의 state가 불변성을 가져야 하는 이유

3. 어떻게 하면 불변성을 가질 수 있을까?

4. state를 직접 변경하지 않고 setState를 써야하는 이유

 

 

1. 불변성이란?

: 값, 상태를 변경할 수 없는 것

 

자바스크립트의 불변성

메모리 영역의 값이 변하지 않는다 = 불변성

 

(1) 원시타입

let a = "data1";
a = "data2";

위 코드에서 변수 a의 값을 변경할 때, 실제로 “data1”이 있는 기존 콜스택 값은 그대로 유지된 채, “data2”를 새로운 콜스택 영역에 할당하고 그 주소로 변수 a가 바라보게 한다.

즉 메모리 영역에서 기존의 데이터가 대체되는 것이 아니라 새로운 영역을 할당하는 것으로, 원시타입은 메모리 영역의 값이 변경되지 않아 불변성을 유지한다.

 

(2) 참조타입

const a = [1, 2, 3];
a.push(100);

배열, 객체와 같은 참조 타입의 경우, 실제 데이터는 메모리 힙에 저장되고, 그 메모리 힙의 주소를 콜 스택의 값으로 저장된다.

즉 변수 a가 바라보고 있는 콜 스택의 값이 변경되지 않고, 메모리 힙에 있는 원본 데이터가 변경이 되기 때문에 불변성이 유지되지 않는다.

 

 

 

 

2. React의 state가 불변성을 가져야 하는 이유

(1) 리액트의 상태 업데이트 방식

  • 리액트는 화면을 업데이트할 때, 이전 상태 값과 얕은 비교를 통해 변경된 사항을 확인한 후 이뤄진다. 즉, 배열이나 객체의 속성 하나 하나를 비교하는 게 아닌, 이전 콜 스택의 주소값과 현재 주소값만을 비교하여 상태 변화를 감지한다.

얕은 비교로 하는 이유?

: 얕은 비교로 상태 업데이트를 하면, 객체의 속성을 모두 비교하는 연산이 줄어들어 효율적이다.

 

(2) 사이드 이펙트를 방지

  • 외부의 원본데이터를 직접 수정하지 않고, 원본 데이터의 복사본을 만들어 값을 사용하게 하여 예상치 못한 오류를 방지할 수 있다.
  • 즉 외부의 원본 데이터를 직접 수정하면, 원본 데이터를 이용하는 다른 곳에 사이드 이펙트가 일어날 수 있으므로 불변성을 지킴으로써 예방한다.

 

 

 

 

3. 어떻게 하면 불변성을 가질 수 있을까?

결국 참조타입의 데이터인 경우에 불변성이 유지되지 않으므로, 새로운 객체나 배열을 생성하여 상태 업데이트를 한다.

  • spread, map, filter, slice, reduce 등 원본 데이터를 이용해 새로운 데이터를 만들어주는 함수를 이용한다.
  • push, pop, splice와 같은 원본 배열을 직접 수정하는 메소드는 안됨!

 

 

 

 

4. state를 직접 변경하지 않고 setState를 써야하는 이유

(1) 리액트의 state는 불변성을 유지해야 한다.

  • 여기서 말하는 state는 "기존 값", setState로 설정하는 값은 "새로 바꿀 값"으로 분리해서 생각하면 된다. 즉 state에 직접 값을 변경하면 안되고, setState를 이용해야 불변성을 유지할 수 있다.
  • 이전 값과 setState를 비교해서 업데이트가 필요한 경우에만 재렌더링이 일어난다. 만약 state를 직접 바꾸려고 하면 재렌더링이 제대로 일어나지 않는다.

 

(2) useEffect

  • 또 직접 state를 변경할 경우 렌더링 문제와 함께 useEffect를 통한 생명주기 제어를 할 수 없기 때문에 이러한 리액트의 핵심 기능을 사용하지 못 할 수 있다.

 

 

 

 

참고 사이트

 

[React] 불변성이란? 불변성을 지켜야 하는 이유

1. 개요 React를 빠르게 배울 때 값을 변경할 때 useState를 사용해야 한다, 불변성을 유지해야 한다, immer를 사용해야 한다, spread 연산자를 사용해야 한다, 공식처럼 생각하고 있었는데 javascript의 메

narup.tistory.com

 

OKKY - 리액트 setState 사용 이유

const [test, setTest] = useState({}); test.value = 1 console.log(test.value); 이렇게 직접 값을 넣어도value값이 넣어지는데setTest를 사용해야 하는 이유가 무엇인가요?

okky.kr