매우 중요: (리액트 컴포넌트에서) 상태 업데이트 시 → 불변성 지키는 것
const onToggle = useCallback((id) => {
setTodos((todos) =>
todos.map((todo) =>
todo.id === id ? { ...todo, checked: !todo.checked } : todo,
),
);
}, []);
[ 구현 ] 기존의 데이터를 수정할 때
→ 직접 수정 x
→ 새 배열 제작 → 새 객체 제작 → 필요 부분 교체
업데이트 필요한 곳에서는 새 배열/객체 제작 하기 때문에
→ React.memo 사용 시 : props 변화 파악해서 리렌더링 성능 최적화 가능
== 기존 값: 직접 수정x & 새로운 값 제작
const array = [1,2,3,4,5];
// 나쁜 예
const nextArrayBad = array; // 똑같은 배열 가리킴 (배열 복사x)
nextArrayBad[0]=100;
console.log(array === nextArrayBad) // 완전 같은 배열 (true)
// 좋은 예
const nextArrayGood = [...array] // 모두 복사 (배열 내부 값)
nextArrayGood[0]=100;
console.log(array === nextArrayGood) // 다른 배열 (false)
const object = {
foo: 'bar',
value: 1
}
// 나쁜 예
const nextObjectBad = object; // 같은 객체 가리킴 (복사x)
nextObjectBad.value = nextObjectBad.value +1;
console.log(object === nextObjectBad); // true (같은 객체)
// 좋은 예
const nextObjectGood = {
...object, // 모두 복사 (기존 내용)
value: object.value+1 // 새로운 값 덮어 씀
}
console.log(object===nextObjectGood) // false (다른 객체)
객체 내부 값 → 새로워져도 바뀐 것 감지 x
→ React.memo에서 최적화(서로 비교) 불가능
얕은 복사 (shallow copy) 하게 됨
= 가장 바깥쪽에 있는 값만 복사
내부 값이 객체 or 배열일 경우
내부 값 따로 복사 해야 함.
예시 코드
const todos = [{id: 1,checked: true},{id:2,checked: true}];
const nextTodos = [...todos];
nextTodos[0].checked=false;
console.log(todos[0]===nextTodos[0]); // true (같은 객체 가리킴)
nextTodos[0]={
...nextTodos[0],
checked:false
}
console.log(todos[0]===nextTodos[0]); // false (새로운 객체를 할당)
불변성 지키면서 새 값 할당 해야 함.
예시 코드
const nextComplexObject = {
...complexObject,
objectInside:{
...complexObject.objectInside,
enabled: false
}
}
console.log(complexObject === nextComplexObject) // false
console.log(complexObject.objectInside === nextComplexObject.objectInside) // false
immer
의 활용
→ 복잡한 상황일 경우
→ 편하게 작업 가능
내부 데이터 < 100개
업데이트 자주 발생 x