불변성

Potato·2023년 4월 8일

TIL

목록 보기
1/10
post-thumbnail

불변성이란?

사전적으로는 "값이나 상태를 변경할 수 없는 것" 이지만 React에서의 불변성이란 State와 연관이 깊다.

JS에서 Object, Array, Function은 모두 참조타입 데이터 이다. 즉, 변수에 할당하면 메모리에 저장된 값을 참조하는데 원시타입 데이터와 달리 참조타입 데이터는 변수에 할당하면 메모리 주소 를 참조하게 된다.


블로그 참조

const array1 = [1, 2, 3]; // 메모리영역 1
const array2 = array; // 메모리영역 1
array2.push(4);
console.log(array1); // [1, 2, 3, 4]

const newArr = [1, 2, 3, 4]; // 메모리영역 2

위 코드를 보면 array1과 array2는 같은 배열을 참조하고 있기 때문에 array2에 push를 하면 array1도 같이 변경된다.

newArr은 새로운 배열을 할당했기에 array1, 2와는 다른 메모리 주소를 참조하고 있다.

"불변성의 의미는 메모리 영역에서 값이 변하지 않는다라는 의미"

리액트 상태 업데이트 원리

리액트는 상태를 업데이트할때 얕은 비교를 수행하는데 이는 객체의 속성을 비교하는게 아니라 이전 참조값과 현재 참조값만을 비교해서 상태 변화를 감지한다. 참조값이란 메모리 주소를 말한다.

const [person, setPerson] = useState({ name: "Alice", age: 25 });

person이라는 객체가 생성되고 이 객체의 메모리 주소를 참조하는 변수 person이 생성된다.

setPerson({ name: "Alice", age: 30 });

setPerson의 인자로 새로운 객체를 넘겨주면 리액트는 새로운 객체와 기존 객체의 얕은 비교를 수행하고 둘이 다른 객체일 경우 새로 만들어진 person의 참조값이 새로운 객체의 메모리 주소를 참조하게 된다.

🛑 얕은 비교: 객체의 최상위 키 값들만 비교

const obj1 = {
  a: 1,
  b: {
    c: 2,
  },
};

const obj2 = {
  a: 1,
  b: {
    c: 2,
  },
};

'a'의 값은 동일해 문제가 없지만 'b'의 값은 객체이며 이 객체의 참조값들이 서로 다르기 때문에 얕은 비교에서는 다른 객체로 간주한다.

깊은 비교에서는 객체의 모든 중첩된 요소까지 비교해 obj1과 obj2를 같은 객체로 간주한다.

다시 돌아와서 이처럼 상태를 바꿀때 객체의 참조값을 바꾸지 않으면 리액트는 상태가 바뀌지 않았다고 판단하고 렌더링을 하지 않는다.

그렇기에 상태를 업데이트할때는 기존 객체를 수정하는 것이 아니라 새로운 객체를 만들어서 상태를 업데이트해야 하고 이 역할을 setState가 해주기때문에 setState를 사용해야 한다.

불변성을 유지하는 방법

새로운 객체를 만들어서 상태를 업데이트하면 된다.

Javasciprt에서는 spread operator, map, filter, slide, reduce 등을 사용해 새로운 객체를 만들 수 있다. 단 splice는 원본 데이터를 변경하니 유의해야하며 spread operator1depth까지만 깊은 복사를 수행하는 것을 유의한다.

혹은 immer.js 같은 라이브러리를 사용한다.

정리

  • 불변성은 메모리 주소를 변경할 수 없는 것.
  • 리액트는 불변성을 지키며 상태 업데이트를 수행해야한다.
  • 불변성 유지를 위해 새로운 객체를 만들어서 상태를 업데이트한다.
  • JS에서는 spread operator, map, filter, slice, reduce 등을 사용해 새로운 객체를 만들 수 있다.
  • immer.js 같은 라이브러리를 사용해도 된다.

개인적으로 공부하며 정리한 글입니다 혹시나 틀린내용이 있다면 알려주시면
정말 감사합니다 😀

0개의 댓글