React에는 useState 말고 state를 관리하기 위한 또다른 React Hook이 있다.
바로 useReducer
useState처럼 state를 생성하고 관리할 수 있게 해주는 React Hook이다.
여러개의 하위 값을 포함하는 복잡한 state를 다뤄야 할 때, useState 대신 useReducer를 사용하면 코드를 훨씬 깔끔하게 쓸 수 있다.
추가로 유지보수도 편해진다.
Dispatch
가 action
을 Reducer
에게 보내면 Reducer
는 action의 내용을 가지고 state를 업데이트 한다.
const [state, dispatch] = useReducer(reducer, initialState);
state
: 컴포넌트에서 사용할 state(상태)dispatch
: 액션을 발생시키는 함수reducer
: 컴포넌트 외부에서 state 업데이트 로직을 담당하는 함수initialState
: 초기 stateconst [money, dispatch] = useReducer(reducer, 0);
useReducer 함수는 첫 번째 매개변수인 reducer가 반환하는 값으로 state를 갱신하는 역할을 한다.
function App() {
const [number, setNumber] = useState(0);
const [money, dispatch] = useReducer(reducer, 0);
return (
<div>
<h2>useReducer 은행에 오신 것을 환영합니다.</h2>
<p>잔고: {money}원</p>
<input
type="number"
value={number}
onChange={(e) => setNumber(parseInt(e.target.value))}
step="1000"
/>
<button onClick={() => dispatch({ type: ACTION_TYPES.deposit, payload: number })}>
예금
</button>
<button onClick={() => dispatch({ type: ACTION_TYPES.withdraw, payload: number })}>
출금
</button>
</div>
);
}
매개변수로 전달된 action을 이용하여 state를 업데이트 하기 위하여 사용된다.
const reducer = (state, action) => {
console.log("reducer가 일을 합니다!", state, action);
switch (action.type) {
case ACTION_TYPES.deposit:
return state + action.payload;
case ACTION_TYPES.withdraw:
return state - action.payload;
default:
return state;
}
};
dispatch({ type: ACTION_TYPES.deposit, payload: number })
dispatch({ type: ACTION_TYPES.withdraw, payload: number })
Action은 state 업데이트를 위한 요구의 '내용'으로 dispatch의 매개변수가 되고, reducer 함수의 두 번째 매개변수가 된다.
const reducer = (state, action) => {
console.log("reducer가 일을 합니다!", state, action);
switch (action.type) {
case ACTION_TYPES.deposit:
return state + action.payload;
case ACTION_TYPES.withdraw:
return state - action.payload;
default:
return state;
}
};
// useReducer의 좋은 점은
// reducer는 전달받은 action대로만 state를 변경시켜 준다.
reducer는 dispatch에 의해 실행되며, state를 업데이트 하는 역할을 담당한다.
reducer는 기존의 state를 변경하거나 추가하거나 덮어쓰지 않고 새로운 state로 대체한다.
import React, { useReducer, useState } from "react";
const ACTION_TYPES = {
deposit: "deposit",
withdraw: "withdraw",
};
const reducer = (state, action) => {
console.log("reducer가 일을 합니다!", state, action);
switch (action.type) {
case ACTION_TYPES.deposit:
return state + action.payload;
case ACTION_TYPES.withdraw:
return state - action.payload;
default:
return state;
}
};
function App() {
const [number, setNumber] = useState(0);
const [money, dispatch] = useReducer(reducer, 0);
return (
<div>
<h2>useReducer 은행에 오신 것을 환영합니다.</h2>
<p>잔고: {money}원</p>
<input
type="number"
value={number}
onChange={(e) => setNumber(parseInt(e.target.value))}
step="1000"
/>
<button
onClick={() =>
dispatch({ type: ACTION_TYPES.deposit, payload: number })
}
>
예금
</button>
<button
onClick={() =>
dispatch({ type: ACTION_TYPES.withdraw, payload: number })
}
>
출금
</button>
</div>
);
}
export default App;