immer.js를 알아보자


리액트를 사용하다 보면 상태(state)를 업데이트할 일이 많다. 그런데 상태를 직접 변경하면 안 되고 setStateuseReducer를 통해 새로운 객체를 만들어야 하는데, 이 과정에서 코드가 지저분해질 수 있다. immer.js는 이런 문제를 해결해주는 라이브러리로, 더 직관적이고 간결한 방식으로 상태를 업데이트할 수 있도록 도와준다.

immer.js란?

immer.js는 불변성을 유지하면서도 더 쉽게 상태를 업데이트할 수 있도록 도와주는 라이브러리다.
리액트에서는 상태를 직접 변경하면 안 되기 때문에, 일반적으로 상태를 변경할 때 새로운 객체를 만들어 반환해야 한다. 하지만 immer.js를 사용하면, 기존 객체를 직접 수정하는 것처럼 보이지만 실제로는 새로운 상태를 생성하는 방식으로 동작한다.

즉, 불변성을 자동으로 관리해주면서 코드의 가독성을 높여주는 역할을 한다.

immer.js 기본 사용법

produce 함수를 사용하여 현재 상태를 기반으로 변경 사항을 적용하는 draft를 제공한다.

설치 방법

npm install immer
# 또는
yarn add immer

기본 사용 예제

import { produce } from "immer";

const state = {
  user: {
    name: "Alice",
    age: 25
  }
};

const newState = produce(state, draft => {
  draft.user.age += 1;  // 기존 상태를 직접 변경하는 것처럼 작성
});

console.log(newState);
// { user: { name: 'Alice', age: 26 } }
console.log(state); 
// { user: { name: 'Alice', age: 25 } }  (원본 상태 유지)

불변성을 자동으로 유지

  • 기존 방식에서는 spread 연산자로 객체를 복사해야 했지만, immer.js는 자동으로 불변성을 보장해준다.
  • produce 내부에서 draft를 수정하는 것처럼 작성하면 immer.js가 새로운 객체를 반환한다.

왜 immer.js를 써야 할까?

리액트에서 상태를 다루다 보면 다음과 같은 코드를 작성해본 적이 있을 것이다.

  const updateCity = () => {
    setUser(prevUser => ({
      ...prevUser,
      address: {
        ...prevUser.address,
        city: "Seoul"
      }
    }));
  };
  • ...prevUser로 기존 상태를 복사하고, 값을 수정할 때까지 반복해줘야 한다.

이럴 때 immer.js를 사용하면 더 짧고 직관적인 코드를 작성할 수 있다.

import { produce } from "immer";

const updateUser = () => {
  setUser(prevUser => produce(prevUser, draft => {
    draft.age += 1;
  }));
};

🎯 리액트에서 immer.js 사용 예제

리액트에서 immer.js를 사용할 때는 위에서처럼 useStateproduce를 함께 사용하면 된다.
하지만 immer.js에서 제공하는 useImmer 훅을 사용하면 더욱 간결하게 상태를 업데이트할 수 있다.

📌 설치 방법

npm install use-immer
# 또는
yarn add use-immer

useImmer를 활용한 상태 업데이트

import React from "react";
import { useImmer } from "use-immer";

const App = () => {
  const [user, updateUser] = useImmer({ name: "Alice", age: 25 });

  const incrementAge = () => {
    updateUser(draft => {
      draft.age += 1;
    });
  };

  return (
    <div>
      <p>{user.name}의 나이: {user.age}</p>
      <button onClick={incrementAge}>나이 증가</button>
    </div>
  );
};

export default App;

useImmer의 장점

useState를 사용할 때와 동일한 방식으로 상태를 관리 가능
updateUser 함수 안에서 produce를 따로 호출할 필요 없이 draft를 직접 수정 가능
✅ 코드가 더 직관적이고 간결해짐

정리

  • immer.js는 불변성을 유지하면서도 직관적으로 상태를 변경할 수 있도록 도와주는 라이브러리
  • produce 함수를 활용하면 기존 객체를 직접 수정하는 것처럼 보이지만, 내부적으로 새로운 상태를 생성
  • 리액트의 useState, useReducer와 함께 사용하면 코드가 훨씬 깔끔해짐

개인적인 감상으론 기존 코드 베이스에 중첩된 상태를 업데이트하는 경우가 많은 경우나 redux를 사용하는 경우에 고려해볼 만 한 라이브러리인 것 같다.