고객이 장부 수정하는 방법을 배워서 (setState를 이용해서) 직접 은행 장부를 수정
근데 고객이 1억명이면, 고객 한 명 한 명이 장부에 기록하는 방법을 모두 안다? 말이 안 된다.
회계 담당자가 들어온 주문 (action) 과 기존의 장부 내용 (state) 을 이용해서 장부의 새 값을 만들어낸다.
useReducer는 ( 비유하자면 ) 은행을 만드는 코드다!
useReducer는 ( 비유하자면 ) 은행을 만드는 코드다!
즉,
이런 요소들을 만드는 은행의 설립자다!
const [count, countDispatch] = ✨useReducer(countReducer, 0)✨;
은행에는 2개의 파라미터가 필요한데,
const [✨count, countDispatch✨] = useReducer(countReducer, 0);
count의 값은 0으로 출발하고(아래 코드의 경우), 장부 변경할 때는 countDispatch (창구 직원) 를 사용한다.
고객은 직접 장부를 기록하지 않고 창구 직원 (countDispatch) 에게 주문 (action) 만 한다.
countDispatch('액션명')
이라는 명령을 내리면 countReducer가 호출되도록 약속되어 있다.
function countReducer(oldCount, action) {
if (action.type === 'UP') {
return oldCount + action.number;
} else if (action.type === 'DOWN') {
return oldCount - action.number;
} else if (action.type === "RESET") {
return 0;
}
}
회계 직원이 주문과 장부의 이전 상태를 보고 장부의 새로운 상태를 만들 듯, countReducer도 마찬가지다.
주문(action)이 'UP'이면 이전 카운트 값에 number를 더한 값을 리턴하고, 그 리턴값이 새로운 count가 된다.
💡사용하는 측에서는 복잡한 로직을 처리하지 않아도 된다.
복잡한 상태를 바꾸는 작업은 전문화된 함수(countReducer == 회계 담당자)가 처리할 수 있게 된다.
💡💡 이전 값과 이후의 값이 상당히 긴밀히 연관되어 있을 때 reducer를 사용하면 상태를 변경시키는 과정을 reducer 함수 안에 은닉할 수 있다.
(reducer를 쓰는 아주 중요한 이유다!)
import React, { useReducer, useState } from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
function App() {
const [number, setNumber] = useState(1);
function countReducer(oldCount, action) {
if (action.type === 'UP') {
return oldCount + action.number;
} else if (action.type === 'DOWN') {
return oldCount - action.number;
} else if (action.type === "RESET") {
return 0;
}
}
const [count, countDispatch] = useReducer(countReducer, 0);
function down() {
countDispatch({type: 'DOWN', number: number})
}
function up() {
countDispatch({type: 'UP', number: number})
}
function reset() {
countDispatch({type: 'RESET', number: number})
}
function changeNumber(event) {
setNumber(Number(event.target.value));
}
return (
<div>
<input type="button" value="-" onClick={down} />
<input type="button" value="0" onClick={reset} />
<input type="button" value="+" onClick={up} />
<input type="text" value={number} onChange={changeNumber} />
<span>{count}</span>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
위 코드처럼 useState와 useReducer를 같이 쓸 수 있다.
이때 useReducer 안에서, useState가 관리하는 state 값이 필요할 때 직접 이 state를 참조하는 건 좋지 않다.
왜냐면 reducer 함수는 순수(pure) 함수기 때문에, input (파라미터)과 output(리턴값)에 의해서만 함수의 동작이 달라져야 하기 때문이다. 외부 요인의 영향을 받으면 안 된다.
그래서 reducer 함수에 파라미터로 전달하는 action을 객체로 바꿔서 그 객체 안에다가 state를 전달하고 있다.