jeong-min.com
❤️‍🔥
Dev

리액트의 핵심, 불변성

2024.09.08

선언형과 함수형

리액트 공식 문서에서 우리는 선언형이라는 표현을 볼 수 있다.
How를 강조하는 명령형 프로그래밍과 달리, 선언형 프로그래밍은 What을 강조한다.
그리고 함수형 프로그래밍은 선언형 프로그래밍을 실현하는 방법 중 하나다.

함수형 프로그래밍의 대표적인 키워드 중 하나는 순수 함수다.
순수 함수란 외부의 값을 변경하는 사이드 이펙트가 없는 함수다.

순수 함수에 대한 더 자세한 내용은 [자바스크립트의 순수 함수와 비순수 함수

](https://www.jeong-min.com/62-pure-impure-function/)에서 확인할 수 있다.

외부의 값을 변경하지 않는다는 개념은 불변성과도 밀접한 관련이 있다.

 

불변성이란?

불변성이란 값이나 상태를 변경할 수 없는 것이다.
그리고 자바스크립트의 원시타입은 불변성을 가진다.

 

자바스크립트의 변수 타입

자바스크립트의 변수 타입에는 크게 원시타입과 참조타입이 있다.
원시타입으로는 string, number, bigint, boolean, null, undefined, symbol이 있고,
나머지는 참조타입으로 볼 수 있다. (object, array, function 등으로 대부분 object로 치환된다.)

원시타입이 변수에 할당될 때, 메모리의 고정 크기로 원시 값이 저장되고 저장된 값을 변수가 가리키게 된다.
(변수와 원시 값은 콜 스택에 함께 저장된다.)

원시타입은 값이 변하지 않는 불변성을 갖고 있기 때문에,
변수 재할당 시 기존 값이 변하는 것처럼 보이지만
실제로는 새로운 메모리에 값이 저장되고 변수가 가리키는 메모리가 달라지게 된다.

 

let a = 1;
a = 2;

첫번째 줄이 실행되면 메모리에 1이 저장되고 변수 a는 1의 메모리 주소를 가리킨다.
두번째 줄이 실행되면 새로운 메모리에 2가 저장되고 변수 a는 2의 메모리 주소를 가리킨다.

 

let a = 1;
let b = a;
a = 2;

두번째 줄이 실행되면 새로운 메모리에 a의 값이 그대로 복사되고 b는 그 메모리의 주소를 가리킨다. 따라서 a가 2로 재할당되더라도 b는 영향을 받지 않는다.

 

그렇다면 참조타입은 어떨까?
참조타입의 가장 큰 특징은 변수의 크기가 동적으로 변한다는 것이다.
따라서 참조 값의 메모리 주소는 콜 스택에 저장되지만, 실제 참조 값 자체는 힙에 별도로 저장하여 사용된다.

let arrA = [];
let arrB = arrA;

arrB.push("abc");
console.log(arrA); // ["abc"]

arrB는 arrA의 데이터의 주소 값을 가리키게 되고,
arrB를 수정하면 arrA 또한 영향을 받게 된다.

 

이처럼 콜 스택에 할당된 값이 바뀌지 않는 원시타입과 달리,
참조타입의 경우 메모리 힙에 할당된 값이 바뀐다.

즉, 불변성은 메모리 영역에서 값이 변하지 않는 것이다.

0

 

리액트의 불변성

리액트는 기본적으로 얕은 비교를 사용하여 props와 state의 변경을 감지한다.
배열이나 객체의 속성 하나하나를 비교하지 않고, 이전 참조값과 현재 참조값만 비교하기에 효율적이다.

const [number, setNumber] = useState(1);
setNumber(2);

const [array, setArray] = useState([]);
setArray([...array, "abc"]);

const [object, setObject] = useState({});
setObject({ ...object, type: 'js' })

따라서 불변성을 가진 원시타입의 경우 바로 업데이트해주어도 되지만,
참조타입의 경우 새로운 참조값을 가진 객체를 생성하여 의도적으로 불변성을 지켜주어야만 한다.

이처럼 리액트는 참조값만 비교하여 상태 업데이트를 효율적으로 수행하고, 불변성을 지켜서 사이드 이펙트를 방지한다.

👇 도움이 되셨다면 👇

B

u

y

M

e

A

C

o

f

f

e

e

© Powered by danmin