intro
안녕하세요. 오늘은 도대체 왜 리액트에서 불변성을 강조하고,
또 불변성을 지키면서 코드를 짜야 하는지 의문이 들어 게시글을 포스팅하게 되었습니다. 그럼 바로 시작해보겠습니다!
불변성이란?
리액트를 공부하다 보면 가장 많이 듣는 단어 중 하나가 바로 '불변성'이죠. 의미는 상태를 직접 수정하지 말고 변하지 않게 하라는 말입니다. 하지만 왜 그렇게 번거롭게 그렇게 해야할까요?
저는 리액트에서 불변성을 지켜야 하는 이유를 3가지로 정리했습니다.
1. 효율적인 상태 변경 감지
리액트는 상태가 변했는지 확인하기 위해 '얕은 비교'를 수행합니다.
리액트에서는 얕은 비교와 깊은 비교가 있는데요, 여기서 얕은 비교는 객체의 깊숙한 곳 까지 일일이 비교하지 않고 성능상 빠르게 비교하는 방식입니다.
상태는 크게 2가지로 구분할 수 있습니다.
가변(mutable)상태와 불변(Immutable)상태이고,
가변: 객체 내부의 값만 바꾸면 메모리 주소(참조값)은 그대로입니다. 리액트 입장에서는 주소가 똑같은 것만 보고, 바뀐게 없다고 판단하여 화면에 리렌더링 시키지 않습니다.
불변: 새로운 객체를 생성하면 메모리 주소가 달라집니다. 리액트는 주소가 바뀐 것을 인지하고 화면을 다시 그리는 리렌더링 과정을 수행합니다.
2. 예측 가능한 렌더링
데이터를 직접 수정하게 되면 의도치 않은 버그가 발생할 확률이 높다고 합니다.
예시로, 여러 컴포넌트가 하나의 객체를 참고하고 있을 때 한 곳에서 데이터를 슬쩍 바꿔버리면, 다른 컴포넌트들은 왜 데이터가 변했는지 모르는 상태에서 화면이 꼬이게 됩니다. 불변성을 지키면 데이터의 흐름이 단방향으로 명확해지고, 상태 변화가 예측 가능해집니다.
3. 리액트의 고급 기능 활용
불변성을 유지한다는 것은 이전 상태의 복사본을 보관하고 있다는 뜻과 같습니다.
Redux와 같은 상태 관리 도구에서 이전 상태로 되돌아가거나, 앞단계로 가는 기능을 배우신 분도 있고, 또 앞으로 배울 분들도 있으실텐데, 이 기능은 바로 이전 상태 객체들이 메모리에 살아있기 때문에 가능한 것입니다.
그러면 어떻게 하면 불변성을 지키는 코드를 작성할까?
리액트에서 불변성을 지키는 가장 대중적인 방법은 스프레드 오퍼레이터나 배열 메서드 (map, filter, concat)등을 사용하는 것입니다. 아래의 예시 코드를 참고해주세요.
// ❌ 나쁜 예: 원본을 직접 수정
const [user, setUser] = useState({ name: 'Choi', age: 25 });
user.name = 'Kim';
// ✅ 좋은 예: 새로운 객체를 생성
setUser({ ...user, name: 'Kim' });
만약 객체의 구조가 너무 깊어 관리가 힘들다면, Immer 라는 라이브러리가 있다고 합니다. 이를 사용하면 마치 직접 데이터를 수정하는 것 처럼! 쉽게 데이터를 변경하며 코드를 짜면서 불변성을 유지할 수 있습니다.
오늘은 간단한 리액트의 불변성과 관련한 게시물을 써봤는데요, 포스팅이 점점 쌓이면서 재미가 조금씩 붙는다는 생각이 좀 듭니다. 좋은하루 보내세요.

'web > react' 카테고리의 다른 글
| 리액트 Context에 대해 알아보고 다크모드를 만들어보자! (feat: custom hook) (0) | 2026.03.30 |
|---|---|
| useRef는 어떻게 데이터를 변화시키지 않을 수 있을까? (0) | 2026.02.27 |
| 리액트 공식문서 과제 오답노트 (0) | 2026.02.19 |
| 리액트 공식문서 - 틱택토 게임 (0) | 2026.02.11 |
| 리액트 기본 - 공식문서 리딩 (0) | 2026.02.11 |