지금 까지 상태를 업데이트 할 때에는 useState
를 사용해서 새로운 상태를 설정해주었지만
useState
말고 useReducer
를 사용하는 방법도 존재한다. useState
는 해당 컴포넌트에서만 관리 가능하지만 useReducer
는 컴포넌트에서 밖이나 다른 파일에서 로직 분리가 가능하다.
예전에 useState
를 익히기 위해 만들어둔 CounterButton.jsx를 사용해 배워보자.
import React, { useState } from "react";
const CounterButton = () => {
const [counter, setCounter] = useState(0);
return (
<>
<div>{counter}</div>
<button
onClick={() => {
setCounter(counter + 1);
}}
>
증가
</button>
<button
onClick={() => {
setCounter(counter - 1);
}}
>
감소
</button>
</>
);
};
export default CounterButton;
function reducer(state, action){
//새로운 상태를 만드는 로직을 넣으면된다.
return nextState;
}
useReducer
는 대게 위와 같은 형태가 기본이라고 생각하면 된다.
현재 상태와 액션 객체를 파라미터로 받아와 새로운 상태를 반환해준다.
reducer에서 반환하는 상태가 컴포넌트들이 지닐 새로운 상태가 된다.
여기서 action
은 업데이트를 위한 정보를 가지고 있다.
액션의 예시는 다음과 같다.
//카운터에 1을 더하는 액션
{
type:"INCREMENT"
}
//카운터에 1을 빼는 액션
{
type:"DECREMENT"
}
//INPUT값을 바꾸는 액션
{
type:"CHANGE_INPUT",
key:"email",
value:"change@email.com"
}
// 새 할 일을 등록하는 액션
{
type: 'ADD_TODO',
todo: {
id: 1,
text: 'useReducer 배우기',
done: false,
}
//
action
객체의 위 처럼 자유롭게 정하면 된다. type
값을 대문자 스네이크케이스로 작성하는 관습이 있긴한데 꼭 그렇게 안해도된다. 우리가 REST API를 사용할때 서버쪽에 BODY데이터를 보낼때를 생각하면된다.
이제 reducer
의 형태를 봤으니 사용해보자.
const [state, dispatch] = useReducer(reducer, initialState);
여기서 state
는 앞으로 컴포넌트에서 사용한 상태값을 뜻하고, dispatch
는 액션을 발생시키는 함수라고 생각하면된다. dispatch({type:"INCREMENT"})
처럼 사용한다.
그리고 useReducer
에 첫번째 파라미터는 reducer 함수를 넣고, 두번째 파라미터엔 초기상태를 넣어주면된다.
이제 useState
로 구현한 CounterButton컴포넌트를 useReducer
로 구현해보겠다.
import React, { useReducer, useState } from "react";
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
}
const CounterButton = () => {
const [counter, dispatch] = useReducer(reducer, 0);
return (
<>
<div>{counter}</div>
<button
onClick={() => {
dispatch({ type: "INCREMENT" });
}}
>
증가
</button>
<button
onClick={() => {
dispatch({ type: "DECREMENT" });
}}
>
감소
</button>
</>
);
};
export default CounterButton;
여기까지 왔다면 궁금한점이 하나 생기셨을것이다.
그럼 어떨때 useState
를 쓰거나 useReducer
를 써야할까?
솔직히 정답은 없다. 편한대로 쓰면된다. 하지만 필자의 경험을 들어 예를 들자면
간단한 값이나 해당 컴포넌트에서만 쓰는 값이라면 useState
를 쓰는게 좋고
객체처럼 복잡한 값을 관리해야 하거나 다양한 컴포넌트에서 쓸 가능성이 있는
상태는 useReducer
를 쓰는게 좋다.