[React] 불변성(Immutability)

rsuubinn·2023년 2월 23일
0

React

목록 보기
1/7
post-thumbnail

코드를 작성하다가 state 값을 변경해줬는데 리랜더링이 한 탬포 늦게 됐었다 🥲
하지만 나는야 리액트 초보자 ... 😶‍🌫️ 왜 이런 현상이 발생하는지 검색하다가 리액트 불변성 에 대해 알게 되었다
그럼 불변성 너 도대체 뭐니?!

📍 변수와 불변성

Javascript 메모리 구조

Javascript 엔진은 3가지의 메모리 공간을 가진다.

  1. Code area

    • 실행한 js 코드를 담는다.
  2. Call stack

    • 실행 중인 함수를 추적하며 계산을 수행하고, 지역 변수를 저장한다.
    • 변수들은 LIFO(후입선출) 형식으로 저장된다.
    • 원시 타입 이 이곳에 저장된다.
  3. Heap

    • 참조 타입 이 할당되는 곳 이다.
    • 콜 스택과 달리 힙의 메모리 할당은 랜덤하게 배치된다.
    • 또한 메모리 누수를 방지하기 위해 JS 엔진의 메모리 관리자가 항상 관리한다.

📍 원시타입과 참조타입

  • 원시타입 : Boolean, String, Number, null, undefined, Symbol
  • 참조타입 : Object, Array

데이터 저장방식

원시타입은 콜스택의 value에 변수 값이 저장된다.
참조타입의 경우 메모리 힙의 주소가 콜스택의 value에 저장되고, 메모리 힙에 변수 값이 저장된다.

변수 할당과 재할당

원시타입

변수 할당

재할당

원시타입의 변수는 변수값이 변경되면 기존 콜스택의 메모리 영역의 value를 변경하지 않고 새로운 메모리 영역에 변경된 변수값을 저장한다.
메모리 영역의 값을 변경할 수 없는 것을 불변성 이라고 한다.
(더이상 참조되지 않는 데이터는 가비지 컬렉터에 의해 적절한 시점에 메모리에서 해제된다.)

참조타입

변수 할당

재할당

참조타입은 기존의 변수를 바꾸는 경우map, spread operator 등 기존의 변수를 변경한 새로운 변수를 반환하는 경우 두 가지를 나눠서 봐야한다.

우선 기존의 변수를 변경하는 경우 를 살펴보면, 변수 값이 변경되면 콜스택의 변화는 없으며, 메모리 힙의 value 값만 변경된다. 즉, 기존의 메모리 영역의 값이 변경되므로 불변성 유지가 되지 않는다.

새로운 변수를 반환하는 경우 에는 새로운 메모리 영역이 생성되기 때문에 불변성 유지가 된다.

원시타입(Boolean, String, Number, null, undefined, Symbol)의 변수들은 콜스택에 값이 저장되고, value가 변경되면 콜스택에 변경된 값을 가지는 새로운 메모리 영역을 생성한다.

참조타입(Object, Array)의 변수 값은 메모리 힙에 저장되고, 콜스택에는 value 값이 저장된 메모리 힙의 주소가 저장된다. 따라서 변수의 값이 변경되면 메모리 힙의 값은 변경되지만 콜스택 값의 변경은 없다.

📍 불변성

불변성은 메모리 영역에서 값을 변경할 수 없다 는 의미이다.

불변성을 지켜야 하는 이유

1) 리액트의 state 변화 감지 기준은 콜스택의 주소값 이다.

리액트는 콜스택의 주소값만을 비교하여 상태 변화를 감지한다. 이를 얕은 비교라고 한다.
리액트의 빠른 state 변화를 감지할 수 있도록 해주는 장점이자, 불변성을 지켜야 하는 이유이다.

원시타입의 경우 메모리 영역값이 변경하지 않는 불변성을 유지한 채로 새로운 메모리 영역에서 변경된 값이 저장되기 때문에 콜스택 주소값의 변화가 감지된다.

하지만 참조타입의 경우 콜스택의 메모리 힙의 주소만을 저장하고, 값은 메모리 힙에 저장, 변경되기 때문에 참조 타입의 값을 변경하면 콜스택의 주소값은 변경이 없어 react는 state의 변경이 없다고 감지하기 때문에 변경된 state는 리랜더링 되지 않는다.

따라서 참조타입의 변경된 값을 react가 감지하기 위해서는 불변성을 유지해야 한다.

2) 불변성을 지킴으로써 사이드 이팩트와 복잡한 코드를 방지할 수 있다.

불변성을 지키는 것은 기존의 메모리 영역에 변경을 가하지 않는 것으로 외부에 존재하는 원본 데이터를 직접 수정하지 않고, 원본 데이터의 복사본을 만들어서 값을 사용하는 것을 의미한다.
이는 기존 메모리 영역의 값이 변경할 경우, 기존 메모리 영역의 값을 사용하는 다른 코드에서 발생할 수 있는 오류를 사전에 방지할 수 있으며, 예기치 못한 오류를 해결할 코드를 추가적으로 만들지 않아도 된다는 이점이 있다.

📍 참조타입의 불변성을 지키는 방법

배열

1) 새로운 배열을 반환하는 메소드 사용

spread operator, map, filter, slice, reduce 등등 새로운 배열을 반환하는 메소드를 활용한다.

2) 기존 배열을 변경하는 메소드 사용할 경우

splice, push원본 데이터를 변경하는 메소드 를 사용해야 한다면, 기존의 배열을 복사한 새로운 객체를 만들고, 복사한 객체의 데이터를 변경한 후에 이를 state에 넣어준다.
이는 state의 property 중 배열인 property에서 특정 원소의 데이터를 변경, 삭제해야하는 경우 매우 유용하다.

객체

setState, useState, useReducer 를 사용하여 상태를 업데이트 할 수 있다.


참고
📝 React의 불변성

이 분 글이 너무 정리가 잘 되어있어서 거의 그대로 작성하니 정리가 된 듯 하다
감사합니다 글쓴이분 🥹

profile
@rsuubinn

0개의 댓글