말하는 컴공감자의 텃밭

React - 불변성 정리 본문

프론트엔드/React

React - 불변성 정리

현콩 2024. 2. 1. 11:56
728x90

React 불변성 정리
불변성이 없는넘..ㅋ

 

자바스크립트 타입에서 원시타입은 불변성을 가지고 있고, 참조 타입은 가지고 있지 않다.

이 둘을 비교하며 확인하고 예제를 통해 정리해보자

 

  •  원시타입
    • 호출 스택에 직접 저장되는 타입.
    • 호출 스택은 코드가 실행될 때 변수와 해당 값을 저장하는 메모리의 일부이다.
    • undefine, null, boolean, number, string, bigint, symbol 이 해당.
    • 불변성을 가지고 있다는 것은 이 타입들의 값을 변경하면 실제 메모리에서 새 값이 생성됨을 말한다.
    • 그렇기에 원래 값은 변경되지 않아 불변한다. 라고 표현한다.
  • 참조 타입
    • 객체, 배열, 함수가 해당
    • 힙에 저장되며, 복잡한 데이터에 사용되는 더 큰 메모리 공간입다.
    • 호출 스택은 실제 데이터가 저장되는 힙 위치에 대한 참조(또는 포인터)를 저장한다
    • 객체를 조작하면 힙에서 해당 객체가 가리키는 메모리 위치의 데이터가 변경된다.
    • 참조 자체를 변경하지 않고도 해당 속성이나 내용을 변경할 수 있기 때문에 가변성을 가진다.

 

그렇다면 불변성을 왜 유지해야하는가?

 

  • 예측 가능성: 불변 데이터의 경우 추적및 예측하기가 더 쉬워 디버깅에 용이하다.
  • 성능 최적화: 불변 데이터는 변경되지 않은 데이터를 재사용할 수 있으므로 성능 최적화에 도움이 된다.
  • 동시성 제어: 다중 스레드 환경에서 불변성은 경쟁 조건과 같은 문제를 피하는 데 효과적이다.

 

// 예시: 원시 타입 (Primitive Types)
let a = 10; // 스택에 저장됨
let b = a;  // 'a'의 복사본이 스택에 생성됨
b = 20;     // 'b'의 값이 변경되어도 'a'의 값은 변하지 않음

// 예시: 참조 타입 (Reference Types)
let obj1 = { value: 10 }; // 힙에 객체가 저장되고, 스택에는 참조가 저장됨
let obj2 = obj1;          // 'obj1'의 참조가 복사됨
obj2.value = 20;          // 'obj2'를 통해 값이 변경되면 'obj1'도 영향을 받음

console.log(a);    // 10, 원시 타입은 불변성을 유지
console.log(obj1); // { value: 20 }, 참조 타입은 가변성을 가짐

 

그렇다면 불변성을 지키는 방법은?

 

참조타입에서 값을 변경한 후, Call Stack 주소 값은 같고 Heap 메모리 값만 바꿔주어 불변성 유지가 어려우므로 새로운 배열을 반환하는 메소드를 사용하면 된다.

 

예제 메서드를 통해 확인해보자.

 

불변성을 지킬 수 있는 즉 새롭게 반환하는 메소드

--> spread operator, map, filter, slice, reduce

 

 

  • Spread Operator (...)
    • 배열이나 객체의 얕은 복사본을 생성한다. 원본에 영향을 주지 않고 복사본을 수정합니다.
const originalArray = [1, 2, 3];
const newArray = [...originalArray, 4]; // originalArray는 변경되지 않음
// 출력값
originalArray: [1, 2, 3] (원본 배열은 변경되지 않음)
newArray: [1, 2, 3, 4] (원본 배열에 4가 추가된 새 배열)

 

  • map () 
    • 호출된 배열의 모든 요소에 제공된 함수를 호출한 결과로 새 배열을 생성합니다.
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2); // numbers는 변경되지 않음
// 출력값
doubled: [2, 4, 6] (각 원소가 2배로 증가된 새 배열)
  • filter ()
    • 제공된 함수의 테스트를 통과하는 모든 요소로 새 배열을 생성합니다.
const numbers = [1, 2, 3, 4, 5];
const evens = numbers.filter(num => num % 2 === 0); // numbers는 변경되지 않음
// 출력값
evens: [2, 4]
  • slice ()
    • 배열의 일부를 새 배열 객체로 얕은 복사하여 반환합니다.
const numbers = [1, 2, 3, 4, 5];
const middle = numbers.slice(1, 4); // numbers는 변경되지 않음
// 출력값
middle: [2, 3, 4] (인덱스 1부터 3까지의 원소를 포함하는 새 배열)
  • reduce ()
    • 배열의 각 요소에 대해 reduce() 함수를 실행하여 단일 출력값을 생성합니다.
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
// 처음에 accumulator는 0이고 currentValue는 numbers 배열의 첫 번째 요소
// numbers는 변경되지 않음
// 출력값
sum: 15 (배열의 모든 요소의 합계)

 

 


 

원본 데이터를 변경하는 메소드

--> splice, push

 

  • splice ()
    • 기존 요소를 제거 또는 교체하거나 새 요소를 제자리에 추가하여 배열의 내용을 변경합니다.
const myArray = [1, 2, 3, 4, 5];
// Remove 3 elements starting from index 1, and add 'a' and 'b'
myArray.splice(1, 3, 'a', 'b');

console.log(myArray); // Output: [1, 'a', 'b', 5]
  • push ()
    • 배열 끝에 하나 이상의 요소를 추가하고 배열의 새 길이를 반환합니다.
const myArray = [1, 2, 3];
myArray.push(4, 5);

console.log(myArray); // Output: [1, 2, 3, 4, 5]

 

728x90

'프론트엔드 > React' 카테고리의 다른 글

React - Redux  (1) 2024.02.07
React - TDD, Testing Library, Jest, expect, matcher  (1) 2024.02.06
React - Memoization  (0) 2024.02.02
React - State, Props, 구조분해할당  (0) 2024.01.31
Comments