React 애플리케이션에서 상태 관리는 매우 중요한 역할을 합니다. 상태를 변경할 때 불변성을 유지하는 것은 필수적입니다. 그러나 직접 객체를 복사하고 수정하는 것은 번거롭고 실수를 유발할 수 있습니다. Immer는 이러한 불편을 해결해 주는 라이브러리로, 상태를 간편하게 관리할 수 있게 도와줍니다.
Immer는 자바스크립트 객체를 안전하게 변경할 수 있도록 돕는 라이브러리입니다. Immer를 사용하면 상태를 직접 수정하는 것처럼 보이지만, 내부적으로는 불변성을 유지합니다. 이를 통해 상태 관리가 훨씬 수월해집니다.
Immer는 npm이나 Yarn을 통해 쉽게 설치할 수 있습니다. 아래의 명령어를 사용하세요.
npm install immer
또는 Yarn을 사용하는 경우:
yarn add immer
Immer를 사용하는 기본적인 방법은 produce 함수를 사용하는 것입니다. produce 함수는 두 개의 인자를 받습니다: 현재 상태와 상태를 변경하기 위한 프로듀서 함수입니다.
아래는 카운터 애플리케이션을 예로 들어 Immer의 사용법을 설명합니다.
import React, { useState } from 'react';
import produce from 'immer';
const Counter = () => {
const [state, setState] = useState({ count: 0 });
const increment = () => {
setState((prevState) =>
produce(prevState, (draft) => {
draft.count += 1; // 드래프트 상태 수정
})
);
};
const decrement = () => {
setState((prevState) =>
produce(prevState, (draft) => {
draft.count -= 1; // 드래프트 상태 수정
})
);
};
return (
<div>
<h1>Count: {state.count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export default Counter;
increment 또는 decrement 함수를 호출하면 setState가 실행됩니다.produce 함수는 현재 상태(prevState)를 인자로 받고, 프로듀서 함수를 호출합니다.draft)를 수정합니다.produce는 수정된 드래프트 상태를 기반으로 새로운 상태를 생성하여 setState로 설정합니다.Immer는 중첩된 객체를 다룰 때 매우 유용합니다. 아래 예제는 Todo 리스트를 관리하는 방법을 보여줍니다.
import React, { useState } from 'react';
import produce from 'immer';
const TodoApp = () => {
const [state, setState] = useState({
todos: [
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Learn Immer', completed: false },
],
});
const toggleTodo = (id) => {
setState((prevState) =>
produce(prevState, (draft) => {
const todo = draft.todos.find((todo) => todo.id === id);
if (todo) {
todo.completed = !todo.completed; // 드래프트 상태를 수정
}
})
);
};
const addTodo = (text) => {
setState((prevState) =>
produce(prevState, (draft) => {
draft.todos.push({ id: Date.now(), text, completed: false }); // 새 TODO 추가
})
);
};
return (
<div>
<h1>Todo List</h1>
<ul>
{state.todos.map((todo) => (
<li key={todo.id} onClick={() => toggleTodo(todo.id)}>
{todo.text} {todo.completed ? '✔️' : '❌'}
</li>
))}
</ul>
<button onClick={() => addTodo('New Todo')}>Add Todo</button>
</div>
);
};
export default TodoApp;
toggleTodo 함수는 특정 Todo 항목의 완료 상태를 토글합니다.addTodo 함수는 새로운 Todo 항목을 추가합니다.produce를 사용하여 상태를 변경합니다.Immer는 기본적인 상태 업데이트 외에도 여러 유용한 기능을 제공합니다.
Immer는 클래스 객체에 대해 불변성을 적용할 수 있도록 immerable 속성을 제공합니다. 이를 통해 Immer는 클래스 인스턴스를 다룰 수 있습니다.
import produce, { immerable } from 'immer';
class Todo {
[immerable] = true; // Immer가 불변성을 적용하도록 표시
constructor(text) {
this.text = text;
this.completed = false;
}
}
// 사용 예제
const todo = new Todo('Learn Immer');
const updatedTodo = produce(todo, (draft) => {
draft.completed = true; // 드래프트 상태 수정
});
Immer는 배열을 다룰 때도 매우 유용합니다. 아래는 배열의 아이템을 추가, 제거, 수정하는 방법을 보여줍니다.
const manageArray = (prevArray) => {
return produce(prevArray, (draft) => {
draft.push('New Item'); // 아이템 추가
draft.splice(1, 1); // 두 번째 아이템 제거
draft[0] = 'Updated Item'; // 첫 번째 아이템 수정
});
};
Immer는 상태를 초기화할 때도 유용합니다. 아래는 상태를 초기화하는 방법을 보여줍니다.
const initialState = {
count: 0,
todos: [],
};
const resetState = () => {
setState((prevState) => produce(prevState, () => initialState));
};
enableAllPlugins와 disableAllPluginsImmer에서는 enableAllPlugins와 disableAllPlugins를 사용하여 모든 플러그인을 활성화하거나 비활성화할 수 있습니다. 이 기능은 특정 상황에서 성능을 조절할 때 유용합니다.
import { enableAllPlugins, disableAllPlugins } from 'immer';
// 모든 플러그인 활성화
enableAllPlugins();
// 모든 플러그인 비활성화
disableAllPlugins();
Immer는 상태를 변경할 때 내부적으로 변경 사항을 추적합니다. 따라서 대규모 상태 트리를 다룰 때는 성능에 영향을 줄 수 있습니다. 이러한 경우에는 다음과 같은 방법을 고려해볼 수 있습니다.
React.memo를 사용하여 컴포넌트를 메모이제이션합니다.Immer는 React에서 불변성을 쉽게 관리할 수 있는 강력한 도구입니다. 중첩된 객체나 배열을 다룰 때 특히 유용하며, 개발 효율성을 높여줍니다. Immer를 사용하면 상태 관리를 더욱 간편하고 직관적으로 할 수 있으므로, React 애플리케이션에서의 사용을 적극 추천합니다.