useState
말고도 useReducer
가 있다. useState
의 확장판이라고 생각하자. ✍️ 다음과 같은 상황에서 사용하면 좋다.
reducer()
는 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수이다.
function reducer(state, action) {
// 새로운 상태를 만드는 로직
// const nextState = ...
return nextState;
}
reducer()
에서 반환하는 상태는 곧 컴포넌트가 지닐 새로운 상태가 된다.action
은 업데이트를 위한 정보를 가지고 있다. 주로 type
값을 지닌 객체 형태로 사용한다.const [state, dispatch] = useReducer(reducer, initialState);
📌 state
앞으로 컴포넌트에서 사용할 수 있는 상태를 가르킨다.
📌 dispatch
액션을 발생시키는 함수이다.
📌 useReducer 의 파라미터
reducer (첫 번째 파라미터) : reducer 함수
→ state 를 변경하는 로직이 담겨 있는 함수
initialState(두 번째 파라미터) : 초기 상태
click 버튼을 누르면 count (state) 값이 증가하도록 만들기
import { useReducer } from 'react';
export default function reducerTest() {
const reducer = (state, action) => { // 2)
if (action.type === 'PLUS') {
return {
count: state.count + 1,
};
}
return state;
};
// dispatch => action 객체를 넣어서 실행
// action => 객체이고 필수 프로퍼티로 type을 가진다.
const [state, dispatch] = useReducer(reducer, { count: 0 }); // 1)
return (
<div>
<p>You clicked {state.count} times</p>
<button onClick={click}> Click me</button>
</div>
);
function click() {
dispatch({ type: 'PLUS' }); // 3)
}
}
1) useReducer Hook
const [state, dispatch] = useReducer(reducer, { count: 0 }); // 1)
<p>You clicked {state.count} times</p> // 1-1)
useReducer()
함수를 사용해서 첫 번째 인자로 reducer 함수를, 두 번째 인자로 state의 초기값이 들어가도록 만든다.
여기서는 우리가 상상하는 초기값 {count:0}
을 넣는다.
useState
에서는 state와 setState를 사용했다. useState
Hook 으로부터 나오는 return은 배열을 반환하고 첫 번째는 현재의 state를, 두 번째 인자는 state를 변경하는 것을 의미했다.
useReducer 반환 배열
1 번째 원소 : 마찬가지로 state를 의미한다. 따라서 1-1)
state에 있는 카운트를 꺼내서 사용할 수 있다.
2 번째 원소 : state를 변경할 수 있는 dispatch함수가 반환된다.
( reducer 에서는 useState의 'setState' 와 같이 사용하지 않고 'dispatch' 라는 이름으로 사용한다. )
2) reducer()
const reducer = (state, action) => { // 2)
if (action.type === 'PLUS') {
return {
count: state.count + 1,
};
}
return state;
};
reducer()
: state 를 변경하는 로직이 담겨 있는 함수
reducer 함수의 파라미터
첫 번째 파라미터 : 이전상태(previous state) 를 의미한다.
두 번째 파라미터 : action 이라고 하는 객체가 들어온다. 즉 state를 조작하려는 객체를 의미한다.
결과적으로 새로운 상태(newState) 를 리턴한다.
즉 이전state와 변경하려는 action 객체가 들어오면 새로운 상태를 만들어서 리턴해주면 된다고 이해할 수 있다.
❓action 객체는 어떻게 들어올까? → dispatch 를 통해서 전달한다. ▼
3) dispatch
const reducer = (state, action) => { // 2)
if (action.type === 'PLUS') { // 3-1)
return {
count: state.count + 1,
};
}
return state; // 3-2)
};
function click() {
dispatch({ type: 'PLUS' }); // 3)
}
2)
의 state에 count
를 +1 증가시키는 액션타입을 담아서 보내준다. 임의의 이름을 붙일 수 있다.action.type
으로 접근가능하다.if
문 조건에 해당되지 않으면 3-2
처럼 그냥 변경없이 state를 return한다.🤔 그렇다면 둘 중 어떤 것을 사용하면 좋을까?
useState
useState
로 관리하는게 편하다.useReducer
컴포넌트에서 관리하는 값이 여러 개로 상태의 구조가 복잡해진다면 useReducer
로 관리하는 것이 편할 수 있다.
→ 즉 다수의 하윗값을 포함하는 복잡한 state일 경우 사용하면 좋다.
다음 state가 이전 state에 의존적인 경우에 사용하면 좋다.
→ 이전 state를 가지고 있다가 action과 함께 조합해서 새로운 state를 만들어 내기 때문이다.😀