React 프로젝트에서 Immer로 불변성 관리 개선하기
문제 상황
회사 프로젝트에서 중첩된 객체 상태를 업데이트할 때마다 스프레드 연산자가 3~4단계로 중첩되는 경우가 많았다.
setState(prev => ({
...prev,
users: {
...prev.users,
[userId]: {
...prev.users[userId],
profile: {
...prev.users[userId].profile,
name: newName
}
}
}
}));
이런 코드가 반복되면서 실수로 불변성을 깨뜨리는 버그가 몇 차례 발생했다.
Immer 도입
Immer는 불변성을 유지하면서도 일반 객체처럼 수정할 수 있게 해주는 라이브러리다.
import produce from 'immer';
setState(produce(draft => {
draft.users[userId].profile.name = newName;
}));
훨씬 직관적이고 실수할 여지가 줄어들었다.
useImmer 훅 활용
use-immer 패키지의 useImmer 훅을 사용하면 더 간편하다.
import { useImmer } from 'use-immer';
const [state, updateState] = useImmer(initialState);
updateState(draft => {
draft.users[userId].profile.name = newName;
});
성능 체크
작은 객체에서는 오히려 오버헤드가 있을 수 있어 Chrome DevTools로 프로파일링을 돌려봤다. 우리 프로젝트에서는 중첩이 깊은 경우가 대부분이라 체감상 차이는 없었고, 코드 가독성 개선이 훨씬 컸다.
결론
복잡한 상태 관리가 필요한 컴포넌트에 Immer를 선택적으로 적용했다. 팀원들 반응도 좋아서 컨벤션에 추가했다. 단순한 상태는 기존 방식을 유지하고, 중첩이 2단계 이상이면 Immer를 쓰는 것으로 가이드를 정했다.