**Immutability(불변성)**란 state를 제자리에서 수정하지 않고, 변경 사항을 담은 새로운 객체/배열을 생성하는 것을 의미합니다. 이는 React, Redux 및 유사한 도구들이 변경을 감지하고 UI를 올바르게 갱신하는 방식의 핵심입니다.
변경(mutation)의 문제
() {
items.(item);
(items);
}
() {
([...items, item]);
}
React(그리고 Redux)는 성능을 위해 깊은 내용이 아니라 참조(oldState === newState)를 비교하여 변경을 감지합니다. 제자리에서 변경하면 참조가 그대로이므로 프레임워크는 아무것도 바뀌지 않았다고 판단하여 리렌더링을 건너뜁니다.
// 배열
setItems([...items, newItem]); // 추가
setItems(items.filter(i => i.id !== id)); // 제거
setItems(items.map(i => i.id === id ? { ...i, done: true } : i)); // 하나 갱신
// 객체
setUser({ ...user, name: "Bob" }); // 필드 갱신
setUser({ ...user, address: { ...user.address, city: "NY" } }); // 중첩 갱신
스프레드 연산자는 얕은 복사본을 만듭니다. 중첩된 데이터의 경우 변경하는 각 레벨을 복사합니다.
✓ 신뢰할 수 있는 변경 감지 → 올바르고 효율적인 리렌더링(참조 동등성)
✓ 참조를 비교하는 성능 최적화 활성화(React.memo, OnPush, useMemo)
✓ 예측 가능한 state — 이전 state가 절대 변경되지 않아 디버깅이 쉬움
✓ 타임 트래블 디버깅 & undo/redo(과거 state 스냅샷 보존)
// Immer(Redux Toolkit에서 사용)는 draft를 "변경"하게 해주며 → immutable 결과를 생성함
produce(state, draft => { draft.items.push(item); }); // 안전 + 가독성
Immer는 draft에 변경처럼 보이는 코드를 작성하게 하고 이를 immutable 갱신으로 변환함으로써, 중첩된 immutable 갱신을 편리하게 만들어 줍니다.
Immutability는 참조 기반 변경 감지가 작동하게 만드는 메커니즘입니다. 이것이 바로 [...items]는 리렌더링을 유발하지만 items.push()는 그렇지 않은 이유입니다.
정확성 외에도, 메모이제이션이 참조를 비교하기 때문에 성능 최적화를 가능하게 하고, 강력한 기능(undo/redo, 타임 트래블)을 열어줍니다.
immutable 갱신 패턴(그리고 Immer 같은 도구)을 이해하는 것은 React/Redux로 올바르게 작업하는 데 필수적입니다. state를 변경(mutate)하는 것은 가장 흔한 초보자 버그 중 하나입니다.
주니어부터 시니어까지 상세한 답변이 포함된 IT 면접 질문 라이브러리.
후원하기