let a = 'first'
// 메모리 공간에 'first' 가 생성되고 식별자 a는 'first'의 메모리 주소를 가리킨다.
let b = a
// 식별자 b도 식별자 a가 가리키는 'first'를 가리킨다.
a = 'second'
// 메모리 공간에 'second'가 생성되고 'first'를 가리키고있던 식별자 a는 이제 'second'를 가리킨다.
console.log(a)
//'second' 가리키는 메모리 공간을 변경했던 대로 'second'가 찍힌다.
console.log(b)
//'first' 여전히 b는 'first'를 가리키고있을 뿐이다
let a = {name:'first'}
let b = a
a.name = 'second'
console.log(a) // {name: "second"}
console.log(b) // {name: "second"}
// 번외
let c = {number : 1}
a = c
console.log(a) // {number: 1}
console.log(b) // {name: "second"}
결론적으로는 불변성을 지키지 않으면 우리는 컴포넌트를 최적화 할 수 없기 때문이다.
예를들어보기 위해
리액트가 컴포넌트를 렌더링하는 과정을 살펴보자.
1.setState를 호출 (혹은 부모로부터 props를 전달 받음)
2.shouldComponentUpdate를 실행했는데 false를 리턴하면 여기서 멈추고, true를 리턴하면 다음 단계로 이동
3.가상 DOM과 실제 DOM을 비교해서 변경사항이 있으면 화면을 다시 그린다
핵심은 2번에 있다. 다음과 같은 2개의 상태를 비교한다고 가정해보자.const array = [1,2,3,4]; const sameArray = array; sameArray.push(5); console.log(array !== sameArray); // false const array = [1,2,3,4]; const differentArray = [...array, 5]; console.log(array !== differentArray); // true
첫 번째 코드의 array와 sameArray변수가 참조하고 있는 배열의 주소 값은 서로 같다. 하지만, 두 번째 코드의 각각의 배열은 다른 레퍼런스를 가지기 때문에 비교했을 때 다르다는 결과 값이 나오게 된다.
이와 같이 불변성을 유지하여 코드를 작성하면 각 객체의 값이 아닌 레퍼런스 값만 비교를 해주면 된다.
즉, shouldComponentUpdate내의 코드는 한 줄이면 컴포넌트를 최적화할 수 있게 된다.
방법1 : 표준함수 사용
- es7 : spread, 배열이라면 concat,map,filter등 기존 배열을 건드리지 않고 새로운 배열을 리턴하는 배열의 고차원 함수도 사용할 수 있다.
- es6 : Object.assign과 Object.freeze를 이용해서 불변성 부여가 가능합니다.
방법 2: immutability-helper를 사용
immutability-helper는 react 공식 문서에서 추천하는 패키지다. 방법 1과는 달리 중첩된 object를 다루기가 쉽다.
방법 3: javascript 라이브러리 immutable-js, immer사용
사용 방법 참고
const a = { name: "모모",
b : {nick : "YJ"}
}
const c = Object.assign({}, a) // 복사
c.name = '콩이' // 복사한 b객체의 name만 변경시도
c.name //'콩이' 변경됨
a.name // '모모' 본래 객체의 name은 변경되지 않음
c.b.nick = "김버섯" // // 복사한 c객체의 프로퍼티 b객체의 nick 변경시도
c.b.nick //"김버섯" 변경됨
a.b.nick //"김버섯" 본래 객체의 프로퍼티도 변경되버림..
// 내부객체는 복사가 안되서 그대로 본래 객체의 주소값을 참조하고 있기 때문에
// 즉 c객체의 b 프로퍼티와 a객체의 b프로퍼티는 같은 주소값을 참고하고있다.
const a = { name: "모모",
b : {nick : "YJ"}
}
Object.freeze(a) // 불변성 부여
a.name = "콩이" // 변경시도
a.name // "모모" 변하지 않음(불변함)
a.b.nick = "블레어" // 내부객체에 변경시도
a.b.nick // "블레어" 변경됨
Object.freeze(a.b) // 내부객체도 불변성 부어
a.b.nick = "김버섯" // 내부객체에 변경시도
a.b.nick // "블레어" 변하지 않음(불변함)
https://poiemaweb.com/js-immutability
https://yuddomack.tistory.com/entry/자바스크립트-변수-파라미터와-메모리-참조
https://velog.io/@kimtaeeeny/
https://medium.com/@ljs0705/
https://github.com/BKJang/dev-tips/issues/42