본 시리즈는 저의 기술면접 경험을 토대로 질문 받았던 내용을 직접 코드를 구현해보면서 이해하자는 목표로 작성한 글입니다 ! 😀
🎤 시작하는 말
Redux 를 사용해봤거나, Redux 를 배우는 입장이라면 듣게되는 말이 있습니다.
'Redux 내부 Store 의 상태는 불변성을 유지해야 한다.'
그래서, Redux 가 불변성을 유지해야 하는 이유가 무엇일까? 하는 물음에서 시작됩니다. 무엇이 불변을 유지 해야하고, 불변성이 가지고 오는 이점은 무엇이며, 어떻게 동작하길래 불변성을 유지해야 하는 것 인지, 그 이유에 대해서 코드를 작성하며 이해해 보려고 합니다.
먼저 Redux 가 불변성을 유지하는 이유를 알려면, 몇가지 알아야할 내용이 있습니다.
📌 불변성이 가지고 오는 이점
Redux 뿐만이 아닌, 통상적으로 불변성을 유지할때의 이점을 생각해보면, App 전체에서 변경되지 않는 데이터가 임의로 변경할 수 있는 데이터보다 추론하기가 더 쉽다.
이는 App의 성능을 향상시키고 프로그래밍 및 디버깅을 단순화할 수 있다.
특히, Web App 의 Context에서 불변성은 정교한 Diff Algorithm 을 간단하고 연산 비용을 줄이도록 구현할 수 있게 하여 연산 비용이 많이 드는 DOM 업데이트 프로세스가 '반드시 필요한 경우'에만 발생하도록 한다.
(다른 라이브러리에 대한 React의 성능 향상의 초석)
정리하자면,
- 데이터의 추론이 쉬워 프로그래밍 및 디버깅의 단순화 및 App 의 성능 향상
- Web App 의 경우, DOM 업데이트 를 위한 Diff Algorithm 의 단순화 및 성능 향상
이 주된 이유인 것이다.
프로그래밍과 디버깅이 단순해 지는것은 어찌보면 당연한 일이다. 항상 데이터가 변하지 않도록 유지가 된다면 언제든 같은 데이터를 가지고 있을것이다.
하지만 Web App 의 성능향상 및 Diff Algorithm 의 성능향상은 아직 와닿질 않는다. 그래서, 어떤부분에서 benefit 이 있길래 단순화 되고 성능향상이 일어난다는 것일까? 불변성이 필요한 이유가 무엇일까? 이를 이해하려면 또 Shallow Equality 를 이해해야 한다.
📌 Shallow Equality ( 얕은 동등성 검사 )
Redux 에서는 내부 Store 의 State 변화 감지를 Shallow Equality 를 통해 검사한다. 그러기 위해선 데이터가 불변성을 유지해야한다.
다음과 같은 데이터가 있다고 가정해보자.
const me = {
ages: 29,
gender: 'man',
birthday: '10-09',
};
const beforeThreeYearsMe = {
ages: 26,
gender: 'man',
birthday: '10-09',
};
Shallow Equality 는 단순히 두개의 다른 변수가 동일한 개체를 '참조' 하는지 확인한다. 따라서 a === b 와 같이 간단하고 빠르다.
const shallowEquality = (a, b) => {
// 매개변수 a 는 me 객체를 참조한다.
// 매개변수 b 는 beforeThreeYearsMe 객체를 참조한다.
if (a === b) {
return 'same';
} else {
return 'diff';
}
};
console.log(shallowEquality(me, beforeThreeYearsMe)); // 'diff'
Deep Equality 는 두 객체의 속성을 일일히 모두 검사 한다. 따라서 각 속성의 값을 비교하며 두 객체의 속성을 통한 재귀 탐색을 포함한다.
let i = 0;
const deepEquality = (a, b) => {
aKeys = Object.keys(a);
bKeys = Object.keys(b);
// key 개수가 다른지 확인
if (aKeys.length !== bKeys.length) {
return false;
}
for (let elem of aKeys) {
// a 객체와 b 객체가 같은 key를 가졋는지 루프 탐색
if (!bKeys.includes(elem)) {
return false;
}
// 같은 key라면 해당 property의 value 값을 타입까지 비교
if (a[elem] !== b[elem]) {
return false;
}
// 원시 값 인 경우 key 를 타입까지 비교
if (!typeof elem === 'object') {
if (elem !== bKeys[i]) {
i++;
return false;
}
}
// 해당 property가 객체라면 재귀탐색
if (typeof elem === 'object') {
let keyEqual = deepEquality(elem, bKeys[elem]);
if (keyEqual !== false) {
return false;
}
}
}
return true;
};
console.log(deepEquality(me, beforeThreeYearsMe)); // false
두 개의 객체를 비교하기 위해 모든 탐색을 할수 있다. 배열인 경우를 제외하고 객체 인지 원시 값인지 를 놓고 간단하게만 비교검사를 했지만, 더 까다로운 검사도 가능할것이다. 객체의 depth 가 깊어지면 깊어질수록, 재귀탐색은 더욱 많아지게 될것이다. 그러다가 수천 번 같음 검사를 수행 할수도 있게되는것이다.
설상가상으로 이 알고리즘은 작업을 완료할 수 없을수도 있다. '순환 참조 객체' 를 생성할 수 있기 때문이다.
이렇게만 비교해보더라도, Shallow Equality 의 성능과 간단함이 훨씬 높음을 알수 있다. 그 전제조건이 데이터가 불변성을 유지 해야하는 것이다.
만약 불변성을 지키지 않는다면 어떻게 될까?
const me = {
ages: 29,
gender: 'man',
birthday: '10-09',
};
const nextMe = () => {
// 지역변수 happyNewYearMe 는 me 객체를 참조한다.
const happyNewYearMe = me;
// 원본 객체를 참조하므로 새로운 객체에 ages 가 더해지는 것이 아닌, 재할당이 이루어진다.
// 이는 의도치 않은 원본의 훼손이 일어나게 된다.
happyNewYearMe.ages++;
return happyNewYearMe;
};
const shallowEquality = (a, b) => {
console.log(a); // ages: 30
console.log(b); // ages: 30
if (a === b) {
return 'same';
} else {
return 'diff';
}
};
console.log(shallowEquality(me, nextMe())); // same
올바른 예시라고하기 어려울수도 있다.
이 경우 비교 검사를 하기전 원본이 변경이 되었기 때문에, Redux 였다면 상태가 변경되지 않았다고 간주할수도 있는것이다.
만약 위의 코드가 불변성을 지켰다면, 다음과 같아야 한다.
const me = {
ages: 29,
gender: 'man',
birthday: '10-09',
};
const nextMe = () => {
// 얕은 복사를 통한 새로운 객체가 생성된다.
// 이로써 원본은 훼손되지 않았고 me 객체는 불변성을 유지했다.
const happyNewYearMe = { ...me };
happyNewYearMe.ages++;
return happyNewYearMe;
};
const shallowEquality = (a, b) => {
console.log(a); // ages: 29
console.log(b); // ages: 30
if (a === b) {
return 'same';
} else {
return 'diff';
}
};
console.log(shallowEquality(me, nextMe())); // diff
이 경우에는 데이터가 변경되었음을 감지하고, Redux 였다면 combineReducers 함수가 새로운 복사본 객체를 반환했을 것이다.
다음 내용에서는 이 combineReducers 함수와 Redux 가 어떻게 Shallow Equality 를 사용하는지 알아보도록 하겠습니다.
참고 문헌 :
Immutable Data | Redux
Table of Contents
redux.js.org
Pros and Cons of using immutability with React.js
React.js is not only a technology for creating dynamic user interfaces. Sure, it is unopinionated about how you structure the rest of your frontend application. But it does not mean that there are no ideas or guidelines that can help you with creating othe
reactkungfu.com
'Front-End > Redux' 카테고리의 다른 글
Redux 의 불변성에 대해 - (2) (0) | 2022.03.25 |
---|