TypeScript+React
useReducer
코딩 화이팅
2023. 9. 3. 13:09
useState vs useReducer
복잡성
useState
간단한 상태를 관리할 때 주로 사용. 예를 들어, 숫자, 문자열, boolean 값 또는 간단한 객체 및 배열과 같은 상태를 관리하는데 적합
useReducer
복잡한 상태 로직이나 여러 값을 포함하는 상태를 관리할 때 주로 사용. 리듀서는 상태 업데이트 로직을 조직화하고 분리하는데 유용
상태 업데이트 로직
useState
상태 업데이트 함수를 호출하여 상태를 변경. 이 함수는 새로운 상태 값을 직접 받거나 상태를 업데이트하는 함수를 받는다.
useReducer
액션 객체를 dispatch 함수에 전달하여 상태를 업데이트. 액션은 리듀서에서 상태 업데이트 로직을 결정하는데 사용
재사용성
useState
상태 로직이 컴포넌트 내부에 존재하기 때문에 재사용성이 어렵다.
useReducer
리듀서 함수는 순수 함수이므로 다른 컴포넌트에서 재사용하기 쉽다.
사용 사례
useState
상태 관리 로직이 간단한 경우, 예를 들어 토글 스위치나 입력 필드의 값을 관리하는데 사용
useReducer
복잡한 상태 관리가 필요한 경우, 예를 들어 여러 상태 값이 상호 작용하는 경우나 상태 업데이트 로직이 복잡한 경우에 사용
언제 무엇을 사용?
- 간단한 상태 : useState는 간단한 상태(예 : 텍스트, 숫자, boolean)를 관리하기 위한 것
- 복잡한 상태 또는 로직 : 상태의 복잡성이나 상태 업데이트 로직이 복잡할 경우 'useReducer'를 사용하는 것이 좋음
- 재사용 가능한 로직 : 로직을 다른 컴포넌트에서 재사용하는 경우, 'useReducer'와 함께 리듀서를 분리하는 것이 좋다.
Counter.tsx
// React 라이브러리에서 useReducer hook을 가져옵니다.
import { useReducer } from "react";
// 카운터의 상태를 설명하는 타입입니다. 현재는 count라는 숫자 속성만 가집니다.
type CounterState = {
count: number;
};
// 액션에 대한 타입입니다. 액션은 type 속성(어떤 종류의 액션인지 설명)과 payload 속성(액션과 관련된 추가 데이터)을 가집니다.
type CounterAction = {
type: string;
payload: number;
};
// 카운터의 초기 상태를 설정합니다.
const initialState = { count: 0 };
// 리듀서 함수입니다. 현재 상태와 액션을 인자로 받아 새로운 상태를 반환합니다.
function reducer(state: CounterState, action: CounterAction) {
switch (action.type) {
case "increment": // "increment" 액션 타입에 대한 처리입니다.
return { count: state.count + action.payload }; // 현재 count 값에 payload 값을 더한 새로운 상태를 반환합니다.
case "decrement": // "decrement" 액션 타입에 대한 처리입니다.
return { count: state.count - action.payload }; // 현재 count 값에서 payload 값을 뺀 새로운 상태를 반환합니다.
default: // 액션 타입이 위의 경우 중 어느 것에도 해당되지 않는 경우 현재 상태를 그대로 반환합니다.
return state;
}
}
export const Counter = () => {
// useReducer hook을 사용하여 카운터의 상태(state)와 상태를 업데이트하는 함수(dispatch)를 가져옵니다.
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count} {/* 현재 count 값을 화면에 표시합니다. */}
{/* "Increment 10" 버튼을 클릭하면 dispatch 함수를 호출하여 "increment" 액션과 payload 값 10을 전달합니다. */}
<button onClick={() => dispatch({ type: "increment", payload: 10 })}>
Increment 10
</button>
{/* "Decrement 10" 버튼을 클릭하면 dispatch 함수를 호출하여 "decrement" 액션과 payload 값 10을 전달합니다. */}
<button onClick={() => dispatch({ type: "decrement", payload: 10 })}>
Decrement 10
</button>
</>
);
};
App.tsx
import "./App.css";
import { Counter } from "./components/state/Counter";
function App() {
return (
<div className="App">
<Counter></Counter>
</div>
);
}
export default App;
Increase를 누르면 10만큼 올라가고 Decrease를 누르면 10만큼 내려간다.
Reset 추가
import { useReducer } from "react";
type CounterState = {
count: number;
};
type UpdateAction = {
type: "increment" | "decrement";
payload: number;
};
type ResetAction = {
type: "reset";
};
type CounterAction = UpdateAction | ResetAction;
const initialState = { count: 0 };
function reducer(state: CounterState, action: CounterAction) {
switch (action.type) {
case "increment":
return { count: state.count + action.payload };
case "decrement":
return { count: state.count - action.payload };
case "reset":
return initialState;
default:
return state;
}
}
export const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "increment", payload: 10 })}>
Increment 10
</button>
<button onClick={() => dispatch({ type: "decrement", payload: 10 })}>
Decrement 10
</button>
<button onClick={() => dispatch({ type: "reset" })}>reset</button>
</>
);
};
- type UpdateAction 부분 추가 : dispatch 함수에 다른 함수가 왔을 때 에러가 발생하지 않아, 확실하게 해주기 위해 type을 지금 있는 increase, decreace로만 받을 수 있게 해줌.
- Reset type 추가 : 어짜피 원래의 수로 돌아오게만 해주면 되기 때문에 payload는 따로 추가해주지 않는다.
- type CounterAction 수정 : 두 타입으로 받을 수 있게 수정해줌.
- case를 추가 : 원래의 값으로 돌아갈 수 있게 return 값을 넣어줌.