자바스크립트에는 원시 타입과 참조 타입이 존재한다.
원시 타입 : Number, String, Boolean, Symbol, Null, Undefined
참조 타입 : Object
깊은 복사 : 기존 값의 주소가 같이 복사되는 것이 아니라 내용만 빼와서 복사된다. 깊은 복사된 값이 변경되어도 기존 값은 변경되지 않고 주소도 새로 생성된다.
얕은 복사 : 기존 값의 주소를 같이 복사해온다. 얕은 복사된 값이 변경되면 기존 값도 같이 변경된다. 🤓🤓
자세한 설명은 여기(JS 얕은 복사 깊은 복사 포스팅)서 확인해 보세요.
리액트는 state 값의 변경이 감지되면 렌더링을 시켜주는데,
주소 값이 변경되었는지만 체크하면 효율적이라는 이유 때문에 얕은 비교를 채택하고 있다.
이때, 원시값의 경우 값이 변경되면 참조한 주소가 아예 변경되니까, 감지되기 쉽다.
하지만 참조값의 경우 같은 주소를 참조하여 복사되니까, 감지되지 않을 위험이 높다.
그래서 리액트에서는 참조값을 불변하게 만들어 주어야 하는 것이다.
불변성을 지키기 위해 우리가 사용해야하는 것은 스프레드 연산자
이다.
참조값을 아예 다른 값으로 변경시켜주어 주소값도 변경해 주는 것이다.
실제로 리스트를 받아오는 배열에 대한 상태를 업데이트할 때
아래 코드와 같이 스프레드 연산자를 사용하는 이유가 여기에 있는 것이다.
setSelectedTagInfo((prevSelectedTagInfo) => ({
...prevSelectedTagInfo,
...newSelectedTagInfo,
}));
이 외에
map
, filter
, slice
, reduce
사용 가능하다.
하지만 splice
, push
는 원본 값을 수정하기 때문에 사용을 지양해야한다.
❗️변경해야하는 참조값이 2 depth 이상일때는 lodash 라이브러리를 사용하자.
❗️원시값은 이렇게해줄 필요가 당연히 없음
📚 압도적 감사 (참고 자료)
라잇의 불변성