useReducer는 상태 관리를 위한 도구이며 조금더 복잡한 상태 로직을 다루는데 useState 보다 적합하게 사용할 수 있다.
const [state, dispatch] = useReducer(reducer, initialArg, init?)
위와 같은 기본형태를 가지고 있다. useState와 비슷하게 상태와 상태를 변경할 수 있는 함수를 반환한다. reducer 함수는 컴포넌트 외부에서 선언되는 함수이며 state, action 2가지 인자를 받는다. initialArg는 초기 상태값이다. init 은 초기값을 동적으로 변경하여 다룰수 있도록 해주는 함수이며 선택적 옵션이다.
예제를 통해 더 자세히 알아보자.
const emailReducer = (state, action) => {
if (action.type === "USER_INPUT") {
return { value: action.val, isValid: action.val.includes("@") };
}
if (action.type === "INPUT_BLUR") {
return { value: state.value, isValid: state.value.includes("@") };
}
return { value: "", isValid: false };
};
const Login = (props) => {
const [emailState, dispatchEmail] = useReducer(emailReducer, {
value: "",
isValid: null,
});
const emailChangeHandler = (event) => {
dispatchEmail({ type: "USER_INPUT", val: event.target.value });
};
const validateEmailHandler = () => {
dispatchEmail({ type: "INPUT_BLUR" });
};
};
enteredEmail, emailIsValid 두개의 상태를 한번에 관리하기 위해 useReducer를 사용했다.
초기 상태는 {value: "", isValid: null} 이며 reducer 함수는 emailReducer로 컴포넌트 외부에 선언했다.
emailChangeHandler 함수는 input 태그가 onChange시에 실행되며 validateEmailHandler 함수는 태그에서 onBlur 될시에 실행된다.
emailChangeHandler 함수를 살펴보자.
함수가 실행 될시 useReducer의 상태변경 함수인 dispatchEmail에 넘기고 싶은값을 넣어 실행된다. (대게 객체를 넘겨준다)
해당 함수가 실행 되면 함수 외부에서 선언한 emailReducer를 실행시키고 전달했던 값은 emailReducer의 action으로 넘겨 받는다.
함수 내부 조건문을 이용해 type을 검사해 값을 return 해주면 해당 값이 최신 상태가 된다.
validateEmailHandler 함수의 dispatchEmail에는 val 을 넘겨주지 않는걸 확인할 수 있다.
onBlur는 의미상 input에서 포커스가 해제됐을때 실행되기 때문에 새로운 값을 평가할 필요가 없다. 즉, 현재 태그에 있는 값을 다시 평가해야 한다.
그러기 위해emailReducer의 조건문에 의해 다른 값이 return 되도록 type만 보내준다.
그 이전의 상태를 참조하려면 emailReducer의 첫번째 인자 state를 이용하면 된다.
다음은 useContext 에 대해 알아보자.