useReducer는 상태가 여러 개일 때, 복잡한 상태 변화 로직을 처리할 때 유용한 React Hook입니다.
주로 여러 개의 상태 값을 한 번에 관리해야 할 때 사용되며,
상태 업데이트가 특정 규칙을 따르는 경우 유용하게 사용할 수 있습니다.
아래 예시는 useState와 useReducer를 각각 사용한 예제를 통해 그 차이를 비교해보겠습니다.
1. useState를 사용한 상태 관리
useState는 간단한 상태를 관리할 때 유용하지만,
상태가 많거나 여러 상태가 서로 연관되어 있을 경우 관리가 복잡해질 수 있습니다.
예를 들어, 데이터를 가져오는 과정에서 로딩 상태, 에러 상태,
그리고 실제 데이터 상태를 관리할 때 useState를 사용하면 아래와 같은 코드가 됩니다.
Post.jsx
import React from "react";
import { useState } from "react";
const Post = () => {
const [loading, setLoading] = useState(false);
const [post, setPost] = useState({});
const [error, setError] = useState(false);
const handleFetch = () => {
setLoading(true);
setError(false);
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((res) => {
return res.json();
})
.then((data) => {
setPost(data);
setLoading(false);
})
.catch((err) => {
setError(true);
setLoading(false);
});
};
return (
<div>
<button onClick={handleFetch}>
{loading ? "Wait..." : "Fetch the post"}
</button>
<p>{post?.title}</p>
<span>{error && "Something went wrong!"}</span>
</div>
);
};
export default Post;
이 코드는 간단하지만,
상태가 많아지면 각 상태 업데이트를 개별적으로 처리해야 하므로 복잡도가 증가합니다.
특히, 상태 변화가 많아질수록 코드가 지저분해지고 유지보수가 어려워질 수 있습니다.
2. useReducer로 상태 관리 개선하기
useReducer는 상태 로직을 분리하고 중앙 집중식으로 관리할 수 있어,
상태가 많거나 복잡한 로직을 처리할 때 유리합니다.
아래는 useReducer를 사용한 코드입니다.
Post.jsx
import React, { useReducer } from "react";
import postReducer, { INITIAL_STATE } from "../hooks/postReducer";
import { ACTION_TYPES } from "../hooks/postActionTypes";
const Post = () => {
const [state, dispatch] = useReducer(postReducer, INITIAL_STATE);
const handleFetch = () => {
dispatch({ type: ACTION_TYPES.FETCH_START });
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then((res) => res.json())
.then((data) => {
dispatch({ type: ACTION_TYPES.FETCH_SUCCESS, payload: data });
})
.catch((err) => {
dispatch({ type: ACTION_TYPES.FETCH_ERROR });
});
};
return (
<div>
<button onClick={handleFetch}>
{state.loading ? "Wait..." : "Fetch the post"}
</button>
<p>{state.post?.title}</p>
<span>{state.error && "Something went wrong!"}</span>
</div>
);
};
export default Post;
useReducer를 사용하면 상태 업데이트를 하나의 reducer 함수에서 처리하므로,
로직이 명확하게 분리되어 유지보수가 쉬워집니다.
dispatch를 통해 상태 변화에 대한 액션을 보낼 수 있고,
postReducer 함수가 상태 변경을 담당하게 됩니다.
reducer와 actionTypes 파일 분리
reducer와 actionTypes를 별도의 파일로 분리하면,
코드의 재사용성과 유지보수성이 더 좋아집니다.
postReducer.js
import React from "react";
export const INITIAL_STATE = {
loading: false,
post: {},
error: false,
};
const postReducer = (state, action) => {
switch (action.type) {
case "FETCH_START":
return {
...state,
loading: true,
error: false,
post: {},
};
case "FETCH_SUCCESS":
return {
...state,
loading: false,
post: action.payload,
};
case "FETCH_ERROR":
return {
...state,
error: true,
loading: false,
post: {},
};
default:
return state;
}
};
export default postReducer;
postActionTypes.js
export const ACTION_TYPES = {
FETCH_START: "FETCH_START",
FETCH_SUCCESS: "FETCH_SUCCESS",
FETCH_ERROR: "FETCH_ERROR",
};
useReducer는 여러 상태를 다루고 복잡한 로직을 처리해야 할 때 매우 유용합니다.
useState로 간단한 상태를 다룰 수 있지만, 상태가 많아지면 useReducer를 사용해보세요.
이를 통해 코드가 더 깔끔하고 관리하기 쉬운 구조로 바뀔 수 있습니다.
참고 자료
https://www.youtube.com/watch?v=RZPAQV7JvNU

'개발 > React' 카테고리의 다른 글
[React] Custom hook 사용법 (0) | 2025.02.20 |
---|---|
[React] Context API 사용법 (0) | 2025.02.20 |
[React] Jest와 React 테스트 환경 설정 (0) | 2025.02.18 |
[React] Redux 미들웨어 사용법 (0) | 2025.02.12 |
[React] React Router를 활용한 페이지 라우팅 (0) | 2025.02.11 |