useState
, useReducer
둘다 state 관리에 유용한 hooks이다.
상태 저장 값과 업데이트하는 함수를 반환한다는 점에서 두가지 기능은 동일하지만 상황에 따라 어떻게 구별해서 사용해야하는지 의문이 들었다. 두 가지 함수를 살펴보며 예시를 만들어보고 비교하여 상황에 맞게 사용할 수 있도록 학습하려 합니다😊
UseState
const [state, setState] = useState(initialState);
state
는 현재 상태를 저장하고setState
는 현재 상태를 업데이트할때 사용하는 함수 입니다. setState에 새 상태 값을 넣어주면 렌더링 대기열에 들어가고 리렌더링 되었을 때 가장 최근에 업데이트된 값을 제공합니다.initialState
은 초기 렌더링시 반환되는 값입니다.
import { useState } from 'react';
#
const Home = () => {
const [data, setData] = useState(1);
console.log(data);
const increase = () => {
setData(data + 10);
console.log(data);
}
const decrease = () => {
setData(data - 10);
console.log(data);
}
return(
<div className="Home">
<div>
<p>숫자 : {data}</p>
<button onClick={increase}>+10</button>
<button onClick={decrease}>-10</button>
</div>
</div>
);
};
버튼을 누르면 setData 함수를 호출하여 data 값을 업데이트 합니다. 새로운 data는 home 컴포넌트에 보내지고 컴포넌트가 리렌더링됩니다.
UseReducer
const [state, dispatch] = useReducer(reducer,initialState);
useState
를 대체하는 함수로 상태를 업데이트 하는 로직을 컴포넌트 바깥으로 분리해서 사용합니다. 컴포넌트를 가볍게 작성할 수 있습니다.
state
: 컴포넌트에서 사용되는 현재 상태
dispatch
: 상태를 변화시키는 reducer 함수를 실행한다.
reducer
: dispatch에서 발생시킨 상태변화를 컴포넌트 밖에서 처리해서 state를 업데이트 시켜준다.
initialState
: 초기 상태
dispatch({ type : "Decrease"})
dispatch 함수를 호출하면 액션객체
를 reducer에 전달한다.
{ type : "Decrease"} : action(=액션 객체)
function reducer(state, action){
switch (action.value){
case "Increase": {
return {count : state.count + 1};
}
case "Decrease": {
return {count : state.count - 1};
}
default: {
throw new Error();
}
}
}
state
와 action 객체
를 인자로 받으며 전달받은 상태변화를 컴포넌트 외부에서 처리하여 state
를 업데이트 시켜준다.
const initialState = {count:0};
초기 state
값을 담습니다.
const initialState = {count:0};
function reducer (state, action) {
switch (action.type) {
case "Increase": {
return {count : state.count + 1};
}
case "Decrease": {
return {count : state.count - 1};
}
case "Multiply": {
return {count : state.count * state.count};
}
case "INIT" : {
return initialState;
}
default : {
throw new Error("Unsupported action type:", action.type);
}
}
}
const DictionaryHome = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return(
<div className="DictionaryHome">
<div className="ex">
<div>값 : {state.count}</div>
<button onClick={() => dispatch({ type : "Increase"})}>+</button>
<button onClick={() => dispatch({ type : "Decrease"})}>-</button>
<button onClick={() => dispatch({ type : "Multiply"})}>*</button>
<button onClick={() => dispatch({ type : "INIT"})}>INIT</button>
</div>
</div>
);
};
Increase
버튼 눌렀음을 가정한다초기값 0에 대해 버튼을 클릭하면 dispatch 함수가 type으로 담아 놓은 객체(=액션객체)를 reducer 함수에 전달합니다. reducer에는 (현재 상태, 액션객체) == (0, "Increase")를 받게 됩니다. Switch문을 통해 액션객체와 일치하는 로직을 타고 새로운 state를 반환하게 됩니다.
useState, useReducer 두 가지 상태관리 함수의 차이를 비교해 보면
useState
는 독립적으로 상태관리를 할 때 적합합니다.
useReducer
는 복잡한 상태 관리가 필요할 때 적합하며 로직을 컴포넌트 바깥으로 분리해서 컴포넌트가 가벼워지고 상태 관리가 용이합니다.