1. useReducer란
컴포넌트 내부에 새로운
State를 생성하는 리액트 훅모든
useState는 useReducer로 대체 가능
2. useState와 useReducer의 차이
useReducer는 상태 관리 코드를 컴포넌트 외부로 분리할 수 있다
useReducer를 사용할 때는 컴포넌트 내부에서는새로운 스테이트를 생성만 하고,
외부에서
reducer라는 이름으로 상태 관리 코드를 작성하여사용할 수 있다.

3. useReducer 사용하는 이유
상태를 외부에서 관리할 수 있는
useReducer라는 훅은 왜 필요할까?리액트의 컴포넌트의 주된 역할은 UI를 렌더링 하는 것이다.
따라서 상태관리 코드가 길고 복잡해지는 경우에는 유지보수 측면에서 좋지 않다.
그래서 이를 따로 분리하여 상태관리를 할 수 있도록 도와주는
useReducer를 사용하는 것이다.앞서 만들어본 투두리스트 앱에서도 상태관리 코드가 너무 길다!

4. 카운터 예제로 활용
간단한 카운트 기능이 있는 예제로 사용 방법을 살펴보자
먼저 예제가 될
Exam컴포넌트를 만들어주자.+버튼과 -버튼이 있는 형태가 될 것이다.
import { useReducer } from "react";
const Exam = () => {
return (
<div>
<h1>0</h1>
<button>+</button>
<button>-</button>
</div>
);
};
export default Exam;useReducer를 사용하기 위해 훅을 불러오고새로운 스테이트를 만들어주자.
여기서 기존에 state에서 상태변화함수가 들어갔던 자리에 있는
dispatch는 발송하다, 급송하다 라는 뜻을 가지고 있으며여기서는 단순히 상태 변화가 있어야 한다고 알리는, 발송하는 함수이다.
import { useReducer } from "react";
const Exam = () => {
const [state, dispatch] = useReducer();
return (
<div>
<h1>0</h1>
<button>+</button>
<button>-</button>
</div>
);
};
export default Exam;컴포넌트에서 상태 변화가 일어나야 한다고
dispatch 함수를 호출하면상태 변화가 요청이 되어
useReducer가 실제로 상태 변화를 일으키는함수를 호출하게 되는데, 이는 직접 만들어야 한다.
이렇게 만든
reducer라는 함수는 useReducer의 첫 번째 인자로 넣어준다.그리고
useReducer의 두 번째 인자로는 초기 값을 넣자.여기까지 했으면 h1의 상수를
state로 넣었을 때 화면에 출력이 된다.import { useReducer } from "react";
function reducer() {};
const Exam = () => {
const [state, dispatch] = useReducer(reducer, 0);
return (
<div>
<h1>{state}</h1>
<button>+</button>
<button>-</button>
</div>
);
};
export default Exam;다음으로 실제로 버튼을 눌렀을 때
dispatch를 호출하여상태 변화를 일으킬 로직을 작성해 주어야 한다.
먼저 플러스 버튼부터 만들어보자.
이벤트 핸들러를 만들고 내부에
dispatch함수를 호출하여인자로 상태가 어떻게 변경될 것인지 객체 형태로 전달한다.
이 객체에서는
type과 data라는 프로퍼티가 들어가게 된다.우리는 1씩 증가시키는 식을 만들고자 하기 때문에
type은 INCREASE, data는 1로 넣어주자.참고로 요청 형태를 담고 있는 이 객체는 액션 객체라고 부른다.
import { useReducer } from "react";
function reducer() {};
const Exam = () => {
const [state, dispatch] = useReducer(reducer, 0);
const onClickPlus = () => {
dispatch({
type: "INCREASE", // 요청 타입
data: 1,
})
}
return (
<div>
<h1>{state}</h1>
<button onClick={onClickPlus}>+</button>
<button>-</button>
</div>
);
};
export default Exam;onClickPlus이벤트 핸들러가 실행될 때,dispatch 함수가 호출되며 useReducer가 실제로상태를 변경하기 위해 변경을 실질적으로 처리하는
reducer라는 함수를 호출하게 된다.ruducer함수의 매개변수로는 먼저 현재 상태인 state를 제공하고두 번째로는 요청의 내용이 담긴
action객체를 제공한다.import { useReducer } from "react";
function reducer(state, action) {
console.log(state, action);
};
const Exam = () => {
const [state, dispatch] = useReducer(reducer, 0);
const onClickPlus = () => {
dispatch({
type: "INCREASE", // 요청 타입
data: 1,
})
}
return (
<div>
<h1>{state}</h1>
<button onClick={onClickPlus}>+</button>
<button>-</button>
</div>
);
};
export default Exam;해당 함수 내에
state와 action을 콘솔에 출력하는 코드를 입력하면출력된 결과를 확인할 수 있다.

콘솔 출력 코드를 삭제하고 그 자리에 조건문으로
action의 type이 INCREASE일 때 action의 data를 현재 state에 더하여반환하는 코드를 작성해주면 플러스버튼의 로직 완성이다.
if (action.type === "INCREASE") {
return state + action.data;
}마찬가지로 마이너스 버튼도 동일하게 만들어주자.
import { useReducer } from "react";
function reducer(state, action) {
if (action.type === "INCREASE") {
return state + action.data;
} else if (action.type === "DECREASE") {
return state - action.data;
}
}
const Exam = () => {
const [state, dispatch] = useReducer(reducer, 0);
const onClickPlus = () => {
dispatch({
type: "INCREASE",
data: 1,
});
};
const onClickMinus = () => {
dispatch({
type: "INCREASE",
data: 1,
});
};
return (
<div>
<h1>{state}</h1>
<button onClick={onClickPlus}>+</button>
<button onClick={onClickMinus}>-</button>
</div>
);
};
export default Exam;만일
reducer 안에 액션들이 많아지는 경우엔 if문보다는switch문을 사용하는 것이 일반적이다.
import { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "INCREASE":
return state + action.data;
case "DECREASE":
return state - action.data;
}
}
const Exam = () => {
const [state, dispatch] = useReducer(reducer, 0);
const onClickPlus = () => {
dispatch({
type: "INCREASE",
data: 1,
});
};
const onClickMinus = () => {
dispatch({
type: "INCREASE",
data: 1,
});
};
return (
<div>
<h1>{state}</h1>
<button onClick={onClickPlus}>+</button>
<button onClick={onClickMinus}>-</button>
</div>
);
};
export default Exam;전체메모
import { useReducer } from "react";
// reducer : 변환기
// -> 상태를 실제로 변화시키는 변환기 역할
// 첫 번째 인수 : 현재 상태
// 두 번째 인수 : 액션 객체
function reducer(state, action) {
console.log(state, action);
switch (action.type) {
case "INCREASE":
return state + action.data;
case "DECREASE":
return state - action.data;
default:
return state;
}
// if (action.type === "INCREASE") {
// return state + action.data;
// } else if (action.type === "DECREASE") {
// return state - action.data;
// }
}
const Exam = () => {
// 첫 번째 인수
// dispatch : 발송하다, 급송하다
// -> 상태 변화가 있어야한다고 알리는, 발송하는 함수
// 두 번째 인수
// 상태의 초기값
const [state, dispatch] = useReducer(reducer, 0);
const onClickPlus = () => {
// 인수 : 상태가 어떻게 변화되길 원하는지
// 객체 형태 -> 액션 객체
dispatch({
type: "INCREASE", // 요청 타입
data: 1,
});
};
const onClickMinus = () => {
dispatch({
type: "DECREASE",
data: 1,
});
};
return (
<div>
<h1>{state}</h1>
<button onClick={onClickPlus}>+</button>
<button onClick={onClickMinus}>-</button>
</div>
);
};
export default Exam;
Share article