1. 불변성
불변성은 어떤 값을 직접적으로 변경하지 않고 새로운 값을 만들어내는 것입니다.
필요한 값을 변형해서 사용하고 싶다면 어떤 값의 사본을 만들어서 사용해야 합니다.
JS에서 원시 타입은 괜찮지만 객체 타입의 불변성을 지키는 것은 고려해야 할 부분이 있습니다.
아래와 같은 코드가 있다고 했을 때 user와 copyUser 변수는 같은 참조(Memory Address) 값을 가집니다. (객체 타입은 참조 값을 주고받습니다.)
그렇기 때문에 user가 가지고 있는 객체의 값이 변경되면 copyUser도 같은 객체를 가지기 때문에 값이 공유됩니다.
하지만 이런 작동 방식은 값을 예측할 수 없게 하거나 버그를 유발하기 때문에 불변성을 통해서 해결합니다.
const user = { name: 'Choi', age: 25 }
const copyUser = user; // 배열의 복사가 아니라 같은 참조 값을 가짐
user.age += 1;
/* user = { name: 'Choi', age: 26 }
copyUser = { name: 'Choi', age: 26 } */
user === copyUser // true
* user와 copyUser는 같은 값을 가집니다.
2. Spread 연산자
새로운 객체에 ...라는 spread operator를 사용하여 복사를 합니다. otherUser는 새로운 객체를 할당 받았기 때문에 user와 otherUser가 가리키는 객체의 참조 값은 다르게 됩니다.
따라서 user의 값 변경은 otherUser의 객체에 영향을 주지 않습니다. (불변성이 잘 지켜졌다고 할 수 있습니다.)
예시로 어떠한 인쇄물을 프린트하면 똑같은 것이 총 두 장 생기는데 한 장의 인쇄물에 낙서를 해도 다른 인쇄물에 영향을 주지 않는 것과 같습니다.
const user = { name: 'Choi', age: 25 }
const otherUser = { ...user }; user.name = 'Lee';
/* user = { name: 'Lee', age: 25 }
otherUser = { name: 'Choi', age: 25 }
*/
user === otherUser // false 서로 다른 참조 값을 가지고 있음
하지만 객체의 깊이가 깊어지면 여전히 문제가 생깁니다. spread operator는 얕은 복사(shallow copy)를 하게 되는데 완전히 다른 객체를 만들고 싶다면 깊은 복사(deep copy)를 해야 합니다.
const user = { name: 'Choi', age: 25, friends: ['Park', 'Kim']}
const otherUser = { ...user };
user.name = 'Lee'; user.friends.push('Kang');
/* user = { name: 'Lee', age: 25, friends: ['Park', 'Kim', 'Kang'] }
otherUser = { name: 'Choi', age: 25, friends: ['Park', 'Kim', 'Kang'] }
*/
user === otherUser // false user.friends === otherUser.friends // true
다음과 같이 불변성을 유지해 줄 수 있지만 객체의 구조가 복잡해질수록 불변성 유지가 힘들어질 것입니다.
그래서 immer과 같은 라이브러리를 사용해 불변성을 유지해 주기도 합니다.
const user = { name: 'Choi', age: 25, friends: ['Park', 'Kim']}
const otherUser = { ...user, friends: [...user.friends] };
user.name = 'Lee';
user.friends.push('Kang');
/*
user = { name: 'Lee', age: 25, friends: ['Park', 'Kim', 'Kang'] }
copyUser = { name: 'Choi', age: 25, friends: ['Park', 'Kim'] }
*/
user === otherUser // false
user.friends === otherUser.friends // false
배열이나 객체를 업데이트 해야 할 때에는 직접 수정 하거나, push, splice 등의 함수를 사용하거나, n 번째 항목을 직접 수정하면 안되고 다음과 같이 concat, filter, map 등의 함수를 사용해야 합니다.
const todos = [
{
id: 1,
text: '할 일 #1',
done: true
},
{
id: 2
text: '할 일 #2',
done: false
}
];
const inserted = todos.concat({
id: 3,
text: '할 일 #3',
done: false
});
const filtered = todos.filter(todo => todo.id !== 2);
const toggled = todos.map(
todo => todo.id === 2
? {
...todo,
done: !todo.done,
}
: todo
);
참조
https://webigotr.tistory.com/293
'FrontEnd > React 기본' 카테고리의 다른 글
[React] React.js 강좌 18. useReducer (0) | 2022.03.08 |
---|---|
[React] React.js 강좌 16. useCallback (1) | 2022.03.08 |
[React] React.js 강좌 15. useMemo (0) | 2022.03.08 |
[React] React.js 강좌 14. useEffect (0) | 2022.03.07 |
[React] React.js 강좌 13. useState (0) | 2022.03.07 |