# 124 [udemy React 완벽 가이드 노트] useReducer및 Reducers
useReducer는 useState와 비슷하게 state를 관리해준다.
그러나 기능이 더 많고
복잡한 state(여러개의 state)에 유용하다.
useReducer가 필요할 때 :
여러개의 state가 함께 속해있는 경우 또는 state가 같이 바뀌거나 서로 관련된 경우
오류의 가능성!
위의 경우엔 useState에서 얻은 것이 관리 사용이 어렵거나 오류가 발생하기 쉽다.
비효율 적이거나 버그가 생길 수 있는 코드가 된다.
예시
Login.js 파일 중 일부
const [enteredEmail, setEnteredEmail] = useState("");
const [emailIsValid, setEmailIsValid] = useState();
const [enteredPassword, setEnteredPassword] = useState("");
const [passwordIsValid, setPasswordIsValid] = useState();
const [formIsValid, setFormIsValid] = useState(false);
state 스냅샷 몇개를 관리하는 login.js파일
서로 관련된 state를 찾아보자
여기 state에는
이메일 또는 비밀번호가 유효한지 관리하는 state, 폼 유효성 관리하는 state
즉 전반적인 form 관련 state라고 할 수 있다.
혹은 각각의 인풋을 두개의 국면을 가지고 있는 하나의 실재인 state라고 할 수 있다.
예를들면 enteredEmail, emailIsValid가 그렇다.
이메일, 비번의 유효성을 확인하여 폼의 유효성을 설정한다.
useEffect 안에서의 setFormIsValid 와
useEffect(() => {
const identifier = setTimeout(() => {
console.log("Checking form validity!");
setFormIsValid(
enteredEmail.includes("@") && enteredPassword.trim().length > 6
);
}, 500);
return () => {
clearTimeout(identifier);
};
}, [enteredEmail, enteredPassword]);
validate... Handler 에서가 그렇다.
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes("@"));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
문제점 1.
Email의 유효성 검사와 Password의 유효성 검사를 useEffect에서 사용하는 방법
그런데 우리는 enteredEmail과 emailIsValid 스테이트를 가지고 있기 때문에
함께 관리할 수 있다.
일단 useEffect를 주석처리하고
다음과 같이 setFormisValid를 추가한다.
useEffect를 사용하기 이전의 코드였다.
const emailChangeHandler = event => {
setEnteredEmail(event.target.value);
setFormIsValid(
event.target.value.includes("@") && enteredPassword.trim().length > 6
);
};
const passwordChangeHandler = event => {
setEnteredPassword(event.target.value);
setFormIsValid(
enteredEmail.includes("@") && event.target.value.trim().length > 6
);
};
이것의 문제점 :
setFormIsValid(
event.target.value.includes("@") && enteredPassword.trim().length > 6
);
이 코드는 두개의 state를 기반으로 formIsValid 스테이트를 업데이트 하고 있다.
리액트가 state 업데이트를 스케줄링 하는 방식에 의해
enteredPassword 스테이트 업데이트가 되기 전에 setFormIsValid가 실행되버리는 경우가 생긴다.
useState의 함수적 갱신을 사용하고 싶겠지만,
58강 참조 (useState의 함수적 갱신) :
https://wha-haha.tistory.com/47?category=950414
# 58 [udemy React 완벽 가이드 노트] useState의 함수적 갱신(Functional updates)
리액트는 업데이트를 바로바로 하지 않기 때문에 동시에 수많은 상태 업데이트를 계획한다면 오래되었거나 잘못된 상태 스냅샷에 의존할 수 있다. 그래서 가장 최근의 스냅샷을 찍어서 그 다음
wha-haha.tistory.com
지금 여기 코드에선 그럴 수 없다.
다음 state업데이트가 동일한 state의 이전 state 스냅샷에 의존하는 경우에만 사용 가능하기 때문.
여기는 두개의 다른 state의 스냅샷에 의존하고 있다.
FormIsValid의 최근 state스냅샷에 의존하는 것이 아니다.
이럴때 useReducer를 사용하면 좋다.
문제점 2.
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes("@"));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
여기에서
다른스테이트를 보고 새로운 emailIsValid state를 도출하는 건 해서는 안된다.
대부분 잘 작동하지만 enteredEmail이 제시간에 처리되지 않을 경우 문제가 생길 수 있다.
이럴경우 함수 폼을 또 사용하고 싶겠지만
같은 state의 최신 state만 얻을 수 있게 된다.
해결 방법 1. 하나의 state로 병합하면 좋다.
다른 state를 기반으로 하는 state를 업데이트 하면
하나의 state로 병합 하는 것이 좋은 방법이다.
email state 하나로 만들어서 관리하면 좋다.
(useReducer를 꼭 사용해야만 좋은 것이 아니다.
적절한 때 사용하도록 하자)
해결 방법 2. useReducer를 써보자.
state가 복잡하고 커지고 여러가지 state가 결합되면
useReducer를 써도 좋은 방법이다.