리액트 애플리케이션을 개발하면서 상태 관리가 점점 더 복잡해질 수 있습니다.
이런 상황에서 리액트가 제공하는 여러 가지 훅을 사용하면 상태 관리가 훨씬 수월해집니다.
이번 글에서는 useReducer, useImmer 두 가지 훅을 살펴보고, 이들이 각각 어떤 상황에서 유용한지, 그리고 어떻게 사용하는지 알아보겠습니다.
1. useReducer란?
useReducer는 리액트에서 상태 관리 로직을 깔끔하게 정리해주는 훅입니다.
useState와 비슷하게 상태를 관리하지만, 상태 변화 로직이 복잡하거나 여러 가지 상태를 한꺼번에 관리해야 할 때 useReducer가 더 유용합니다.
useReducer 기본 사용법
const [state, dispatch] = useReducer(reducer, initialState);
- reducer: 상태를 어떻게 바꿀지 정의하는 함수입니다. 상태와 액션을 받아 새로운 상태를 반환합니다.
- initialState: 상태의 초깃값입니다.
- dispatch: 상태를 업데이트하기 위해 호출하는 함수로, 액션을 전달하여 상태를 변화시킵니다.
예제 코드
예제를 통해 useReducer의 사용법을 살펴보겠습니다. 사용자가 할 일을 추가하고, 완료 상태를 변경하며, 할 일을 삭제할 수 있습니다.
function todoReducer(todos, action) {
switch (action.type) {
case "added":
return [...todos, { id: action.id, text: action.text, completed: false }];
case "toggled":
return todos.map((todo) =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case "deleted":
return todos.filter((todo) => todo.id !== action.id);
default:
throw new Error(`알 수 없는 액션 타입: ${action.type}`);
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(todoReducer, []);
const [text, setText] = useState("");
const handleAddTodo = () => {
dispatch({ type: "added", id: todos.length + 1, text });
setText("");
};
return (
<div>
<h1>todoList</h1>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="할 일을 입력하세요"
/>
<button onClick={handleAddTodo}>추가</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
onClick={() => dispatch({ type: "toggled", id: todo.id })}
style={{ textDecoration: todo.completed ? "line-through" : "none" }}
>
{todo.text}
</span>
<button onClick={() => dispatch({ type: "deleted", id: todo.id })}>
삭제
</button>
</li>
))}
</ul>
</div>
);
}
useReducer에 대한 더 자세한 내용은 https://react.dev/reference/react/useReducer 을 참조해 주세요.
useReducer – React
The library for web and native user interfaces
react.dev
2. useImmer란?
useImmer는 상태를 쉽게 업데이트할 수 있도록 도와주는 훅입니다.
리액트에서 상태를 변경할 때는 기존 상태를 직접 수정하지 않고, 새로운 상태를 만들어서 교체하는 방식(불변성 유지)을 사용하는 것이 일반적입니다.
하지만 이 방식은 중첩된 객체나 배열을 다룰 때 번거롭고 복잡할 수 있습니다. useImmer를 사용하면 상태의 불변성을 신경 쓰지 않고도 마치 상태를 직접 수정하는 것처럼 쉽게 업데이트할 수 있습니다.
useImmer는 내부적으로 불변성을 자동으로 관리해 주므로, 코드를 간결하고 직관적으로 작성할 수 있습니다.
useImmer 기본 사용법
const [state, updateState] = useImmer(initialState);
- updateState: 상태를 변경할 때 사용하는 함수입니다. 불변성을 자동으로 처리해주므로, 복잡한 상태를 직관적으로 업데이트 할 수 있습니다.
예제 코드
import { useImmer } from 'use-immer';
function TodoApp() {
const [todos, updateTodos] = useImmer([
{ id: 1, text: "리액트 배우기", completed: false },
]);
const [text, setText] = useState("");
const handleAddTodo = () => {
updateTodos((draft) => {
draft.push({ id: todos.length + 1, text, completed: false });
});
setText("");
};
const toggleTodo = (id) => {
updateTodos((draft) => {
const todo = draft.find((t) => t.id === id);
if (todo) todo.completed = !todo.completed;
});
};
const deleteTodo = (id) => {
updateTodos((draft) => {
const index = draft.findIndex((t) => t.id === id);
if (index !== -1) draft.splice(index, 1);
});
};
return (
<div>
<h1>할 일 목록</h1>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="할 일을 입력하세요"
/>
<button onClick={handleAddTodo}>추가</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span
onClick={() => toggleTodo(todo.id)}
style={{ textDecoration: todo.completed ? "line-through" : "none" }}
>
{todo.text}
</span>
<button onClick={() => deleteTodo(todo.id)}>삭제</button>
</li>
))}
</ul>
</div>
);
}
useImmer를 사용하면 복잡한 상태 업데이트를 더 쉽게 할 수 있고, 코드도 깔끔해집니다.
useImmer에 대한 더 자세한 내용은 https://immerjs.github.io/immer/ 을 참조해 주세요.
Introduction to Immer | Immer
Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
immerjs.github.io
'React > 정리' 카테고리의 다른 글
React Router(CSR) 활용법 (0) | 2024.08.21 |
---|---|
리액트 전역 상태 관리: useContext 훅 (0) | 2024.08.12 |
useState, useEffect (0) | 2024.08.12 |
JSX 문법 (0) | 2024.08.11 |
Create React App (0) | 2024.08.11 |