useState를 사용하면 너무 번거로운 경우,
너무 많은 일들을 처리해야 하는 경우,
관련 state 스냅샷들이 서로 독립적이고 한큐에 업데이트가 잘 안 될 때
예를들어 많은 state가 같이 있거나 여러 state가 한번에 바뀌거나 sate끼리 관련된 경우를 말한다.
현재 이 상황에서는 불필요한 state가 너무 많다. 자세히 보면 email입력, 검증을 하나로 묶을 수 있을것 같고 pw입력, 검증을 하나로 묶을 수 있을 것 같다.
그리고 코드를 보면 사실 앞서 포스팅한것 처럼 state를 업뎃을 할땐 이렇게 스냅샷에만 의존하면 버그가 발생하여 함수사용을 권장한다 했었다. 하지만 여기선 그렇게 할 수 없다. 왜냐하면 다음 state 업데이트가 동일한 state의 이전 state의 스냅삿에 의존하는 경우에만 가능하기 때문이다. 하지만 위 코드에서는 서로 다른 두개의 state의 스냅샷에 의존하고있기 때문에 물가능하다.
즉, 위와같이 2개의 서로 다른 state를 한큐에 업뎃할 때 사용하면 좋다.
또는 state를 기반으로 state를 업뎃하는 경우에
- useReduer는 조금 더 효과적으로 실행되어야 할 때 쓰면 좋다고 배웠다
- state value들이 많이 있을 때
- 업데이트 로직이 많이 복잡하거나 할 때
- 개별적으로 관리되며 서로 연관되어있는 state일 때
const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn);
useReducer도 useState처럼 2개의 배열을 반환한다.
state : 최신 state 스냅샷
dispatchFn : 위의 state 스냅샷을 업데이트할 수 있는 함수 (액션을 디스패치(최신화)함)
reducerFn : 액션을 소모하는 함수, 최신 state 스냅샷과 디스패치된 액션을 자동으로 가져오는 함수
reducerFn 은 컴포넌트함수 외부에 선언되는데 그 이유은 컴포넌트 함수 내부에서 만들어진 어떤 데이터도 필요하지 않기 때문이다. 그리고 어차피 react가 알아서 보내주기 때문에
initialState : 초기값
initFn : 초기 state를 설정하기위해 실행해야하는 함수 (http request의 결과)
prev~~
매개변수로 state 최신값을 가져와서 업뎃을 했는데 2개의 state를 사용해야하다 보니 일반적인 state로는 해결이 불가능해서 Reducre의 dispatch 함수를 사용하여 action을 추가하여 state를 최신화하는 것이다.import { useState } from "react";
const useInput = (validateValueFn) => {
const [enteredValue, setEnteredValue] = useState("");
const [isTouched, setIsTouched] = useState(false);
const valueIsvalid = validateValueFn(enteredValue);
const hasError = !valueIsvalid && isTouched;
const valueChangeTrigger = (event) => {
setEnteredValue(event.target.value);
};
const inputBlurTrigger = () => {
setIsTouched(true);
};
const reset = () => {
setEnteredValue("");
setIsTouched(false);
};
return {
value: enteredValue,
isValid: valueIsvalid,
hasError,
valueChangeTrigger,
inputBlurTrigger,
reset,
};
};
export default useInput;
import { useReducer } from "react";
const initialInputState = {
value:"",
isTouched:false
}
const inputStateReducer = (state, action) => {
if(action.type==="INPUT"){
return{ value: action.value, isTouched: state.isTouched }
} else if (action.type==="BLUR") {
return{ isTouched: true, value: state.value }
} else if (action.type==="RESET") {
return { isTouched: false, value: "" }
} else {
console.log("something is wrong in user-hook")
}
return {
// new state snap shot
// 하지만 위의 조건을 충족시키지 못 했다면 초기화 구문임
initialInputState
};
}
const useInput = () => {
const [inputState, dispatch] = useReducer(inputStateReducer, initialInputState);
const valueIsvalid = inputState.value.trim() !== "";
const hasError = !valueIsvalid && inputState.isTouched;
const valueChangeTrigger = (event) => {
dispatch({type:"INPUT", value:event.target.value});
};
const inputBlurTrigger = (event) => {
dispatch({type:"BLUR"});
};
const reset = () => {
dispatch({type:"RESET"})
};
return {
value: inputState.value,
isValid: valueIsvalid,
hasError,
valueChangeTrigger,
inputBlurTrigger,
reset,
};
};
export default useInput;