[React] useReducer - state를 생성하는 리액트 훅(React Hook)
이번 글은 state를 생성하는 리액트 훅인 useReducer에 대한 글이다.
[ useReducer ]
useReducer : 컴포넌트 내부에 새로운 state를 생성하는 react hook
=> 모든 useState는 useReducer로 대체가 가능하다
차이점 : 상태관리코드를 컴포넌트 외부로 분리할 수 있다. (외부에 분리할 수 있는 것이 useReducer / 내부에서만 사용할 수 있는 것이 useState)
[ useReducer 사용법 ]
state를 사용할 때처럼 아래 코드를 import해줘야한다.
import { useReducer } from "react";
아래 코드와 같이 useReducer()를 선언해준다.
[ useReducer() 내부 구조 ]
이때 dispatch는 상태변화를 요청하는(알리는) 함수이고
=> dispatch 함수 호출 ➡️ 상태 변화 요청 ➡️ UseReducer가 상태 변화를 실제로 처리할 함수(내가 만든 reducer함수 / useReducer()안에 인수로 들어있는 것)를 호출
useReducer()의 인수로 상태변화를 처리할 함수 reducer와 state의 초기값을 넣어준다.
=> reducer()는 컴포넌트 밖에 위치한다.
const [state, dispatch] = useReducer(reducer, 0);
버튼 클릭 시 해당 함수 onClickPlus이 실행될 수 있도록 코드를 작성하고 해당 함수를 정의한다.
※ 이때 dispatch()가 사용되는데 dispatch는 reducer함수에 요청할 내용을 객체 형태로 받는다.
(dispatch는 onClick()같은 상태 변화가 실행되는 시작점에서 호출시켜줘야함)
=> type은 상태를 어떻게 변화시키고자 하는지 작성한다.
이때 받은 객체들은 액션 객체라고 부른다.
const onClickPlus =()=> {
dispatch({
type: "INCREASE",
data: 1,
});
};
아래 코드와 같이 reducer()의 인수로 state의 초기값과 dispatch의 객체 값을 받아와서 사용할 수 있다.
아래 코드에서는 값이 'INCREASE'인지 'DECREASE'인지에 따라 반환하는 값을 다르게 해준다.
function reducer(state, action) {
switch(action.type){
case 'INCREASE': return state+action.data;
case 'DECREASE': return state-action.data;
default: return state;
}
}
이때 콘솔창에 action을 출력하게 하면 아래 사진과 같이 출력된다.
=> Q: 상태 변화 함수도 없는데 어떻게 state를 변경하는가?
=> A: reducer함수에서 새로운 state 값을 반환하고 그 값을 useReducer()가 불러와 state 값을 변경해준다.
[ 전체 코드 ]
import { useReducer } from "react";
function reducer(state, action) {
switch(action.type){
case 'INCREASE': return state+action.data;
case 'DECREASE': return state-action.data;
default: return state;
}
}
const Exam = () => {
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;
[ 총정리 ]
액션 객체(type)를 인수로 전달 후 dispatch()를 호출 ➡️ useReducer()가 요청을 처리하기 위해 실제로 상태를 변화시키는 reducer(useReducer()의 인수에 있는)를 호출 ➡️ reducer()는 매개변수로 현재의 state 값을 제공, 요청이 담긴 action 객체를 제공
=> dispatch() 호출 ➡️ reducer() 호출 ➡️ dispatch()의 액션 객체가 reducer()의 매개변수로 전달
=> state를 어떻게 변경시키는가 : reducer()에서 새로운 state 값을 반환 ➡️ 반환 값을 useReducer()가 불러와서 실제로 state 값을 변경시켜줌 (이때 reducer()의 인수 state에는 useReducer()에서 설정한 초기값이 들어가고 action에는 dispatch()의 액션 객체가 들어감)