728x90
반응형
React의 톺아보기! 🎛️
React에서 상태 관리를 할 때, 가장 먼저 떠오르는 도구는 useState죠. 하지만 상태가 복잡하거나 여러 상태가 서로 얽혀 있을 때는 useReducer가 훨씬 깔끔하고 유지보수가 쉬운 선택이 될 수 있습니다. 이번에는 useReducer의 기본부터 실무 활용까지, 모든 것을 다뤄볼게요!
useReducer란 무엇인가요? 🤔
useReducer는 리듀서 패턴을 기반으로 한 React의 상태 관리 Hook입니다. 리듀서 패턴은 reducer 함수와 action을 사용해 상태를 업데이트하는 방식으로, Redux와 유사한 구조를 제공합니다.
언제 useReducer를 사용할까요?
- 상태가 여러 개의 값으로 구성되어 복잡한 경우
- 상태 업데이트 로직이 명확히 구조화되어야 할 때
- 상태 관리와 관련된 액션이 다양할 때
useReducer의 기본 문법 🛠️
문법 구조
const [state, dispatch] = useReducer(reducer, initialState);
- reducer: 상태 업데이트 로직을 정의한 함수
- initialState: 상태의 초기값
- state: 현재 상태 값
- dispatch: 상태를 업데이트하기 위해 action을 보내는 함수
useReducer 기본 예제 📘
카운터 예제: 가장 기본적인 useReducer 사용법
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
default:
throw new Error("Unknown action type");
}
}
function Counter() {
const initialState = { count: 0 };
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
export default Counter;
코드 해석
- reducer 함수:
- state: 현재 상태 값
- action: 상태를 업데이트하는 명령(객체 형태)
- switch문으로 action.type에 따라 상태 업데이트 로직을 정의
- dispatch 호출:
- dispatch는 action 객체를 전달받아 reducer를 실행시킵니다.
useReducer의 장점 🌟
- 명확한 상태 관리: 상태 업데이트 로직이 하나의 함수에 모여 있어 가독성과 유지보수성이 뛰어남
- 복잡한 상태 처리: 여러 상태가 얽혀 있을 때도 간단하게 관리 가능
- 액션 기반 업데이트: 어떤 상태 변화가 어떤 액션에 의해 발생했는지 명확히 알 수 있음
useReducer 실무 활용 예제 💼
1. 복잡한 폼 상태 관리
import React, { useReducer } from "react";
function formReducer(state, action) {
switch (action.type) {
case "SET_FIELD":
return { ...state, [action.field]: action.value };
case "RESET":
return { username: "", email: "" };
default:
throw new Error("Unknown action type");
}
}
function Form() {
const initialState = { username: "", email: "" };
const [state, dispatch] = useReducer(formReducer, initialState);
const handleChange = (e) => {
dispatch({ type: "SET_FIELD", field: e.target.name, value: e.target.value });
};
const handleReset = () => {
dispatch({ type: "RESET" });
};
return (
<div>
<input
name="username"
value={state.username}
onChange={handleChange}
placeholder="Username"
/>
<input
name="email"
value={state.email}
onChange={handleChange}
placeholder="Email"
/>
<button onClick={handleReset}>Reset</button>
<p>Username: {state.username}</p>
<p>Email: {state.email}</p>
</div>
);
}
export default Form;
핵심 포인트
- 여러 상태(username, email)를 하나의 리듀서에서 관리
- 상태를 업데이트하는 로직이 한 곳에 모여 있어 코드가 깔끔
2. 비동기 작업 처리
useReducer와 useEffect를 결합하면 비동기 상태 관리도 쉽게 처리할 수 있어요.
import React, { useReducer, useEffect } from "react";
function dataReducer(state, action) {
switch (action.type) {
case "FETCH_INIT":
return { ...state, isLoading: true, isError: false };
case "FETCH_SUCCESS":
return { ...state, isLoading: false, data: action.payload };
case "FETCH_FAILURE":
return { ...state, isLoading: false, isError: true };
default:
throw new Error("Unknown action type");
}
}
function DataFetcher({ url }) {
const initialState = {
isLoading: false,
isError: false,
data: [],
};
const [state, dispatch] = useReducer(dataReducer, initialState);
useEffect(() => {
const fetchData = async () => {
dispatch({ type: "FETCH_INIT" });
try {
const response = await fetch(url);
const result = await response.json();
dispatch({ type: "FETCH_SUCCESS", payload: result });
} catch (error) {
dispatch({ type: "FETCH_FAILURE" });
}
};
fetchData();
}, [url]);
return (
<div>
{state.isError && <p>Error fetching data.</p>}
{state.isLoading ? (
<p>Loading...</p>
) : (
<ul>
{state.data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
)}
</div>
);
}
export default DataFetcher;
useReducer vs useState: 언제 무엇을 선택할까? ⚖️
기준 | useState | useReducer |
복잡도 | 단순한 상태 관리에 적합 | 복잡한 상태 관리와 여러 액션 처리에 적합 |
상태 변경 로직 | 컴포넌트 내부에서 직접 상태를 업데이트 | 리듀서를 통해 상태 변경 로직을 분리 |
코드 구조 | 간단하고 빠르게 구현 가능 | 코드가 조금 더 길어지지만 명확한 구조 제공 |
가독성 | 간단한 상태에는 가독성 좋음 | 복잡한 상태에서는 가독성 뛰어남 |
주의사항 🧐
- 리듀서 함수는 순수 함수로 작성해야 합니다.
- 같은 입력 → 항상 같은 출력
- 부수 효과(side effects) 발생 금지
- 초기 상태에 유의하세요.
- initialState를 명확히 정의하지 않으면 상태 초기화에 혼란이 생길 수 있음
- 액션 타입 관리
- 액션 타입은 문자열이므로 오타나 실수를 방지하려면 상수로 관리하는 것이 좋음
const ACTIONS = {
INCREMENT: "increment",
DECREMENT: "decrement",
};
결론: useReducer로 상태를 정복하자! 🏆
React의 useReducer는 복잡한 상태를 관리하고 액션 기반으로 로직을 구조화하는 데 최적화된 도구입니다. 적재적소에 사용한다면, 코드의 가독성과 유지보수성이 크게 향상될 거예요.
🌷전설의 개발자가 되어봅시당! 🌷
728x90
반응형
'Front-end > React' 카테고리의 다른 글
[React] 커스텀 훅(Custom Hook): 당신의 코드, 더 스마트하게! ✨ (0) | 2024.12.12 |
---|---|
[React] useCallback: 함수 메모이제이션의 정석! 🛠️ (0) | 2024.12.11 |
[React] useEffect: 라이프 사이클 관리자 🔮 (2) | 2024.12.09 |
[React] useMemo: 성능 최적화를 위한 비장의 무기 🛡️ (1) | 2024.12.08 |
[React] Hooks: 초보부터 전문가까지 완벽 정복 🪝 (1) | 2024.12.07 |