
Reducer란?
reducer는 상태(state)를 업데이트하는 함수로, 주로 Redux나 useReducer 훅을 사용할 때 등장하는 개념입니다.
기본개념
- reducer는 현재 상태(state)와 액션(action)을 받아서 새로운 상태를 반환하는 순수 함수입니다.
- 기존 상태를 직접 변경하는 게 아니라, 새로운 상태를 반환하는 방식으로 동작합니다.
기본 구조
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
case "DECREMENT":
return { count: state.count - 1 };
default:
return state; // 기본적으로 현재 상태를 유지
}
}
위에서 state는 현재상태를 가르키며,
action은 상태를 변경하는 객체 형태(예를들면 { type: "INCREMENT" } )입니다.
switch 문을 사용해서 action.type에 따라 새로운 상태를 반환 합니다.
React useReducer 훅에서 사용
react에서 useReducer를 사용하여 상태관리를 할 수 있습니다.
import { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
case "DECREMENT":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
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>
</div>
);
}
- useReducer(reducer, initialState)를 사용하면 상태(state)와 상태를 변경하는 dispatch함수가 반환됩니다.
- dispatch({type: 'INCREMENT'}) 를 호출하면 reducer가 실행되어 상태가 업데이트 됩니다.
Redux에서 사용
redux에서는 reducer 가 전체 어플리케이션의 상태를 관리하는 역할을 합니다.
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
case "DECREMENT":
return { count: state.count - 1 };
default:
return state;
}
}
// Redux Store 생성
const store = createStore(counterReducer);
redux에서는 store를 생성할때 reducer(위에서 counterReducer) 를 넘겨주면 전체 상태 관리를 할 수 있습니다.
그렇다면 언제 Reducer를 사용해야할까요?
- useState로 관리하기 어려운 복잡한 상태를 다룰때 useReducer 활용
- Redux를 사용할 때 전역 상태를 관리할 때
- 상태 변경 로직을 한 곳에서 관리하고 싶을 때
👉 단순한 상태(Boolean 값이나 간단한 string)는 useState로 충분하지만, 다양한 액션에 따라 상태가 변하는 경우에는 useReducer나 redux의 reducer를 사용하는게 좋다
👉 여러 개의 상태(state)를 관리해야 하거나, 상태 변경이 여러 액션(action)에 따라 달라지는 경우
1) useState로 관리하기 복잡한 경우
예: 폼 입력 상태관리
// AS-IS
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
// TO-BE
const initialState = {
name: "",
email: "",
password: "",
};
function reducer(state, action) {
return {
...state,
[action.field]: action.value,
};
}
const [state, dispatch] = useReducer(reducer, initialState);
<input
type="text"
value={state.name}
onChange={(e) => dispatch({ field: "name", value: e.target.value })}
/>;
여러개의 useState를 관리하는 대신, 하나의 reducer로 여러 상태를 한꺼번에 업데이트 가능합니다.
2) 다양한 액션에 따라 상태가 변하는 경우
예1: 모달 상태관리 (모달이 여러개인 경우)
const initialState = {
isLoginModalOpen: false,
isSignupModalOpen: false,
};
function reducer(state, action) {
switch (action.type) {
case "OPEN_LOGIN":
return { ...state, isLoginModalOpen: true, isSignupModalOpen: false };
case "OPEN_SIGNUP":
return { ...state, isSignupModalOpen: true, isLoginModalOpen: false };
case "CLOSE_ALL":
return { ...state, isLoginModalOpen: false, isSignupModalOpen: false };
default:
return state;
}
}
- OPEN_LOGIN, OPEN_SIGNUP, CLOSE_ALL 같은 다양한 액션을 처리할 수 있음
- useState를 각각 만들어서 관리하면 코드가 길어지지만, useReducer를 사용하면 더 깔끔하게 관리 가능
예2: 복잡한 상태변화( 로딩, 성공, 에러상태)
const initialState = {
loading: false,
data: null,
error: null,
};
function reducer(state, action) {
switch (action.type) {
case "FETCH_START":
return { loading: true, data: null, error: null };
case "FETCH_SUCCESS":
return { loading: false, data: action.payload, error: null };
case "FETCH_ERROR":
return { loading: false, data: null, error: action.error };
default:
return state;
}
}
// 사용 예시
dispatch({ type: "FETCH_START" });
fetchData()
.then((data) => dispatch({ type: "FETCH_SUCCESS", payload: data }))
.catch((error) => dispatch({ type: "FETCH_ERROR", error }));
결론
▷ 상태가 단순한 boolean이나 string이라면 useState 사용
▷ 여러 상태를 한 번에 관리해야 하거나, 액션이 다양하면 useReducer가 더 효율적
▷ 비동기 처리(loading, success, error` 상태 관리)나 다양한 UI 상태 관리(모달, 폼, 토글 등)에 적합
🔥 결론: 상태 업데이트 로직이 점점 복잡해진다면 useReducer를 고려하는 게 좋다! 🔥
'내직업은 IT종사자 > javascript' 카테고리의 다른 글
debounce와 throttle의 개념 및 차이 (1) | 2024.11.29 |
---|---|
useRoute()로 라우팅 정보 가져오기 (0) | 2024.10.15 |
lodash 라이브러리 chunk 란? (0) | 2024.10.11 |
ECMA2022.js #을 사용해서 private variable, method 선언 방법 및 구조 (0) | 2024.08.08 |
ealry return 은 좋은 것일까? (0) | 2024.05.08 |