안녕하세요 ~ YB 김가현입니다 😋
4주차 파트 중 객체 state 업데이트하기, 배열 state 업데이트하기에 대해 알아보겠습니다 ~
state 업데이트 큐 파트는 3주차에서 다루었던 batching에 대한 내용이더라구요 ! 그래서 해당 파트를 제외한 객체 state 업데이트하기, 배열 state 업데이트하기에 대해 알아보도록 하겠습니다 !
React state에서 객체를 올바르게 업데이트 하는 방법
Javascript의 객체에는 어떤 값이든 저장할 수 있습니다. 이 때 객체의 속성을 직접적으로 변경하는 것을 Mutation이라고 하는데, 이는 권장되지 않는 방식입니다. 왜냐하면 React는 효율적으로 상태 변화를 감지하고 컴포넌트를 리렌더링하기 위해 불변성(immutability)을 요구하기 때문입니다. 상태를 직접 변경하면 리액트가 변경 사항을 제대로 인식하지 못할 수 있어 예상치 못한 동작이 발생할 수 있습니다.
따라서 React state에 있는 객체를 업데이트하려면, 직접 객체를 변경하는 것이 아니라
새 객체를 생성하고 (혹은 기존 객체의 복사본을 만들고), 이를 사용해야 합니다.
이는 곧 state에 저장한 자바스크립트 객체는 어떤 것이라도 읽기 전용인 것처럼 다루어야 한다 라는 말과도 연결지어 생각할 수 있습니다.
코드로 살펴보자면,
import { useState } from 'react';
export default function MovingDot() {
const [position, setPosition] = useState({
x: 0,
y: 0
});
return (
<div
onPointerMove={e => {
position.x = e.clientX;
position.y = e.clientY;
}}
style={{
position: 'relative',
width: '100vw',
height: '100vh',
}}>
<div style={{
position: 'absolute',
backgroundColor: 'red',
borderRadius: '50%',
transform: `translate(${position.x}px, ${position.y}px)`,
left: -10,
top: -10,
width: 20,
height: 20,
}} />
</div>
);
}
position object는 현재 포인트의 위치를 나타내고 있습니다.
하지만 해당 코드를 실행시켜보면, 커서의 위치로 빨간 점이 이동하고 있지 않습니다.
React는 state 설정 함수가 없으면 객체가 변경되었는지 알 수 없기 때문에, 아무 동작도 하지 않아서 제대로 동작하지 않는 것인데요,
리렌더링을 발생시키려면 아래와 같이 코드를 수정해주면 되겠죠 ?
onPointerMove={e => {
setPosition({
x: e.clientX,
y: e.clientY
});
}}
*단, local mutation은 괜찮습니다 !!!
이미 state에 존재하는 객체를 변경할 때만 문제가 되는 것이고, 다른 코드가 해당 객체를 참조하지 않는 경우는 문제가 되지 않습니다.
전개 문법으로 객체 복사하기
만약 기존 데이터를 새로 만드는 객체의 일부로 포함시키고 싶다면, 모든 속성을 개별적으로 복사할 필요가 없도록 객체 전개 구문을 사용할 수 있습니다.
setPerson({
...person, // 이전 필드 복사
firstName: e.target.value // 새로운 부분은 덮어쓰기
});
... 객체 전개 구문을 사용하면 모든 프로퍼티를 각각 복사하지 않아도 됩니다.
대신 … 전개 구문은 “얕은” 구문으로 한 단계 깊이만 복사한다는 점에 유의해야 합니다.
중첩된 객체 업데이트하기
아래와 같이 중첩된 객체가 있을 때, person.artwork.city를 업데이트 하고 싶다면 어떻게 해야 할까요 ?
const [person, setPerson] = useState({
name: 'Niki de Saint Phalle',
artwork: {
title: 'Blue Nana',
city: 'Hamburg',
image: '<https://i.imgur.com/Sd1AgUOm.jpg>',
}
});
먼저 (이전 객체의 데이터로 생성된) 새로운 artwork 객체를 생성한 뒤, 그것을 가리키는 새로운 person 객체를 만들어야 합니다.
setPerson({
...person, // 다른 필드 복사 (그대로 사용)
artwork: {
...person.artwork, // 동일한 값 사용
city: 'New Delhi' // New Delhi로 덮어씌우기
}
});
Immer로 간결하게 갱신 로직 작성하기
Immer는 쉽게 불변성을 유지하면서 업데이트를 도와주는 라이브러리입니다.
우리가 상태를 업데이트 할 때, 불변성을 신경쓰지 않으면서 업데이트를 하면 Immer 가 불변성 관리를 대신 해주는 셈이죠.
const Obj = {
user: {
name: {
first: '리스',
last: '나'
},
age: 25,
address: {
city: '마포구',
state: '서울특별시',
}
},
};
위 객체의 이름과 주소를 변경하고자 할 때, 전개연산자를 사용하여 불변성을 유지하려 하면 코드가 다소 지저분해집니다.
const updatedObj = {
...Obj,
user: {
...Obj.user,
name: {
...Obj.user.name,
last: "김",
},
address: {
...Obj.user.address,
city: "강남구",
},
},
};
뎁스가 깊은 데이터 값을 수정하면 할수록 위와 같이 복잡한 코드를 만나게 됩니다.
왜냐하면 전개연사자를 통해 중첩된 객체나 배열을 복사할 때는 객체의 최상위 레벨만 복사되고 중첩된 객체 배열은 참조값이 복사되기 때문이죠 ! 이 때 Immer를 사용하면, 간단하게 지저분한 코드 문제를 해결할 수 있습니다.
import produce from 'immer';
const updatedObject = produce(originalObject, (draft) => {
draft.user.name.last = '김';
draft.user.address.city = '강남구';
});
첫 번째 인자로는 복사 대상의 객체를, 두 번째 인자로는 해당 객체의 업데이트 함수를 넣어주면 됩니다.
🧐 그렇다면, 무조건 Immer를 사용하면 될까요 ?
그렇지 않습니다. Immer를 사용하면 JS의 기본 내장 함수를 이용해 작업하는 것보다 성능이 떨어집니다.
물론 데이터가 몇 만개씩 있는게 아니라면 그닥 성능 차이가 나진 않겠지만요 ..
immer은 ES6의 Proxy를 활용하는데 구형 브라우저나 react-native 같은 환경에서는 지원되지 않기 때문에 ES5 fallback를 사용하게 된다고 해요. 이렇게 될 경우 꽤나 느려지게 됩니다 (191ms 정도라고 해요. 참고로 인간이 시각적으로 인지 할 수 있는 최소 딜레이는 13ms 라고 합니당 . 꽤나 느려지죠 ..)
그래서 Javascript만으로는 해결이 불가능한 경우에 immer를 쓰라고 권장하고 있습니다. 가능하다면 데이터의 구조가 복잡해지는 것을 방지할 것 …⭐️⭐️
아래 내용을 참고해보셔도 좋을 것 같아요 !
23. Immer 를 사용한 더 쉬운 불변성 관리 · GitBook
No results matching ""
react.vlpt.us
React state에 저장된 배열을 올바르게 업데이트 하는 방법
객체와 마찬가지로 React state에서 배열도 읽기 전용으로 처리해야 합니다. 따라서 배열 내부의 항목을 재할당하거나, push(), pop() 같은 함수로 배열을 변경하면 안됩니다.
배열에 항목 추가하기
- concat
- […arr]
배열에서 항목 제거하기
- filter
- slice
배열에서 항목 교체하기
- map
배열 정렬하기
- 배열을 복사한 뒤 reverse나 sort 사용하기
+) 객체는 실제로 배열 내부에 위치하지 않는다 ?
공식문서를 읽을 때 이해가 안 됐던 말인데요 😳
배열의 요소로 객체를 사용할 때 객체가 배열 내부에 "복사"되는 것이 아니라 객체의 참조가 배열에 저장된다는 의미라고 합니다. 객체의 주소를 배열에 저장해서 배열이 해당 객체를 참조할 수 있게 하는거죠 .
배열과 객체는 둘 다 참조 타입이므로 객체가 배열에 저장되면 배열과 객체는 같은 객체를 참조하게 됩니다. 객체가 배열에 저장될 때 변경 사항이 다른 변수에도 영향을 미친다는 것을 알고 있어야 하고, 배열이나 객체를 state로 관리할 땐 꼭 꼭 주의하기 ~ 😶 !!!
'나야, 리액트 스터디' 카테고리의 다른 글
[week4] 객체 state 업데이트 하기 (2) | 2024.11.18 |
---|---|
[week4] - 상호작용성 더하기 - State 업데이트 큐, 객체 state 업데이트하기, 배열 state 업데이트하기 (3) | 2024.11.17 |
[week4] 객체 state 업데이트 하기, 배열 state 업데이트하기 (3) | 2024.11.17 |
[week4] 상호작용성 더하기 - State 업데이트 큐, 객체 state 업데이트하기, 배열 state 업데이트하기 (4) | 2024.11.17 |
[week3]- 이벤트처리 (4) | 2024.11.11 |