사전적으로 불변성이란 '변하지 아니하는 성질' 을 의미합니다.
위 문장만으로는 불변성의 의미를 정확하게 이해되지 않기 때문에
불변성을 이해하기 위해서는 개력적으로나마 메모리와 데이터에 대한
지식의 이해가 필요합니다.
원시타입 vs 참조타입
원시타입: Boolean, String, Number, null, undefined, Symbol
참조타입: Object, Array
기본형은 불변성(immutability)를 가지고 있습니다. 불변성인 기본형은 값이 변하지 않는것일까요?? 예시를 통해 설명해보겠습니다.
01 let string = 'abc';
02 string = 'd';
03 console.log(string); // d가 출력됨
위 예시를 보면 사전적으로 정의 된 불변성으로는 설명이 되지 않는 결과를 출력하게 됩니다.
하지만 반은 맞고 반은 틀립니다. string 값이 'abc' -> 'd'로 변경 된 것처럼 보이지만,
실제 메모리 영역에서는 'abc', 'd' 둘 다 존재합니다.
❓ 메모리에서 무슨일이?
기존 문자열에 어떤 변환을 가하든 무조건 새로 만들어 별도의 공간에 저장한다는 사실을 알 수 있습니다. 즉, 불변성의 진짜 의미는 메모리 영역에서 값은 변경할 수 없다로 해석 가능합니다.
(메모리에 대한 이해가 더 필요할 것 같습니다..)
리액트에서 불변성을 지켜주는 이유는 리액트가 상태 업데이트를 하는 원리 때문입니다. 리액트는 상태값을 업데이트 할 때 얕은 비교를 수행하게 되는데, 이런 이유로 종종 배열이나 객체를 업데이트 할때
setState([...state, newState]),
setState({...state, [key]: value})
이런식으로 배열이나 객체에 spread문법을 사용해 참조값을 만들어 상태를 업데이트 합니다.
이런 행위가 불변성을 지켜주는 것이고, 불변성을 지켜줌으로써 얻게 되는 이점은 바로 사이드 이펙트를 방지하는 것입니다.
예를들면
-참조타입인 객체나 배열의 경우 새로운 값을 변경할 때
원본 데이터가 변경 됩니다(불변성이 지켜지지 않음)
이렇게 원본 데이터가 변경될 경우, 이 원본데이터를 참조하고 있는 다른 객체에서
예상하지 못한 오류가 발생할 수 있습니다.
-spread operator, map, filter, slice, reduce, concat 등등 새로운 배열을 반환하는 메소드들을 활용하면 됩니다.
-setState를 이용할 때 원시타입 경우에는 값을 바로 넣어주어도 되지만
참조타입인 경우에는 새로운 객체나 배열을 생성한 후 값을 넣어주어야 합니다.
//원시타입
const [number, setNumber] = useState(0)
setState(1)
//참조타입 spread연산자
const [todo, setTodo] = useState({text: '할일1', checked: true})
setTodo({...todo, text:'블로그 올리기'})
참조:
https://www.beta-labs.in/2020/09/js-datatypes-operators.html
https://hsp0418.tistory.com/171
http://www.yes24.com/Product/Goods/78586788