react basic - 얕은 복사와 깊은 복사에 따른 useEffect()와 useMemo()의 차이점

조해빈·2023년 6월 3일
0

짧은이론

목록 보기
22/22

Shallow

얕은 복사(Shallow Copy):

원본 객체나 배열의 주소값을 복사하여 새로운 변수에 할당하는 방식

복사된 변수는 원본과 동일한 객체나 배열을 참조하게 됩니다. 따라서, 원본 객체나 배열이 변경되면 복사된 변수에도 영향이 갈 수 있다.

얕은 복사는 내부 객체나 배열의 참조값을 공유하기 때문에, 내부 객체나 배열이 변경되면 복사된 변수에도 영향을 줄 수 있다.

얕은 비교(Shallow Comparison): 주소값 비교

const obj1 = { name: "John", age: 30 };
const obj2 = { name: "John", age: 30 };
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];

console.log(obj1 === obj2); // false
console.log(arr1 === arr2); // false

적절한 예제인 지는 모르겠지만.... 어쨌든 위의 예제에서 obj1 === obj2와 arr1 === arr2를 비교하면 모두 false를 반환한다.

객체와 배열의 주소값이 서로 다르기 때문인데 즉, 얕은 비교는 객체나 배열이 참조되는 주소값을 비교하는 것이다.

const originalArray = [1, 2, 3];
const shallowCopy = originalArray;

shallowCopy[0] = 10;
console.log(originalArray); // [10, 2, 3] 원본도 변경됨

Deep

깊은 복사(Deep Copy):

원본 객체나 배열의 모든 값을 재귀적으로 복사하여 새로운 객체나 배열을 생성하는 방식

복사된 변수는 원본과 별개의 객체나 배열을 참조하게 된다. 고로 원본 객체나 배열의 변경이 복사된 변수에 영향을 주지 않는다.

const originalObject = { name: "John", age: 30 };
const deepCopy = { ...originalObject };

deepCopy.age = 40;
console.log(originalObject); // { name: "John", age: 30 } 원본은 변경되지 않음

깊은 비교(Deep Comparison): 값 비교

const obj1 = { name: "John", age: 30 };
const obj2 = { name: "John", age: 30 };
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];

console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // true
console.log(JSON.stringify(arr1) === JSON.stringify(arr2)); // true

위의 예제에서는 JSON.stringify()를 사용하여 객체와 배열을 문자열로 변환한 뒤, 문자열을 비교하고 있다. 이렇게 하면 객체와 배열의 내용을 비교하게 되는 것이다.

== vs === ?

여기서 잠시 == vs === 의 차이는 뭘까?

== (동등 연산자):

두 개의 피연산자를 비교할 때, 값을 비교하기 전에 형 변환을 수행한다. 형 변환 후에 값이 같은지를 비교하는 것이다. 고로 동등 연산자는 얕은 비교를 수행하며 깊은 비교를 보장하지 않는다고 말할 수 있다.

=== (일치 연산자):

두 개의 피연산자를 비교할 때, 자료형과 값을 모두 비교하는 것! 깊은 비교를 수행한다고 말할 수 있다.
비교 연산자에 대해서는 오히려 원시 타입 vs 객체 타입이라고 생각해야겠다.

원시 (Primitive): 단순 변수는 스택(stack) 메모리에 할당된다. 스택은 변수의 값과 함께 호출 스택(call stack)에 저장된다.

할당받는 메모리 공간의 크기가 상대적으로 작다.

객체 (Objects): 객체는 힙(heap) 메모리에 할당된다. 힙은 동적으로 크기가 조정되는 메모리 영역으로서, 객체나 복잡한 데이터 구조를 저장하는 데 사용된다. 객체는 힙에 할당되고, 이 객체에 대한 변수는 해당 객체를 참조하기 위한 포인터를 가지게 되는 것이다.

객체의 경우, 변수는 해당 객체를 참조하기 위한 포인터를 가지며, 객체의 크기나 구조가 변경되어도 해당 변수는 해당 객체를 계속 참조한다.

힙에 할당되므로 더 큰 메모리 공간이 필요하다.

useEffect()

기본적으로, useEffect() 내에 작성하는 첫번째 인자, 콜백 함수 () => {}는 랜더링을 할 때마다 랜더 완료 직후에 수행되는 함수이다.

이때 useEffect()의 두번째 인자로 의존성 배열(dependency array)을 넣는다면, useEffect()는 의존성 배열(dependency array)에 지정된 값들의 주소 값을 비교하여 변경 여부를 확인한다.

모습이 아래와 같이 되는 거다.

useEffect(() => {
 
}, [dependencyArr]); // 👈 의존성 배열

이렇게 되면 이전 렌더링과 현재 렌더링 사이에 의존성 배열 내 주소 값 변경이 있었을 경우에만 콜백 함수가 실행한다.

따라서, useEffect()는 의존성 배열에 대한 얕은 비교(Shallow comparison)를 통해 랜더 전후 의존성 배열의 주소 값의 변경 여부를 확인하는 훅이라 이해할 수 있다.

useMemo()

반면 useMemo는 배열을 순회하여 의존성 배열 내의 값들의 내용을 비교하여 변경 여부를 확인한다.

이전 렌더링과 현재 렌더링 사이에 의존성 배열의 값(value)이 변경되었을 경우에만 메모이제이션된 값을 다시 계산합니다. 값의 내용을 비교하는 것은 얕은 비교가 아닌 깊은 비교(Deep comparison)인 것!

고로 useMemo()는 의존성 배열에 대한 깊은 비교(Deep comparison)를 통해 랜더 전후 의존성 배열의 내용에 대한 변경 여부를 확인하는 훅이라 이해할 수 있다.





.
.

  • useEffect는 의존성 배열 내 값들의 주소 값 변경 여부를 확인
  • useMemo는 의존성 배열 내 값들의 내용 변경 여부를 확인
profile
UE5 공부하는 블로그로 거처를 옮겼습니다!

0개의 댓글