useReducer
React(리액트)에서는 useReducer란 훅(Hook)을 제공하는데, 이 reducer(리듀서)로 상태 관리(state management)를 할 수 있다. useState와 비슷하지만 가령 두 개의 상태가 컴바인 되어 관리되어야 할 경우 같은(아이디 상태 값, 아이디 유효성 검사 통과 여부 상태 값) 조금 더 복잡한 상태 관리가 필요할 때 사용할 수 있다.
useReducer 문법은 간단하다. reducer(리듀서) 함수와 initialState(초기 상태)를 전달하면 useReducer라는 훅(Hook)이 새로운 상태(state)와 dispatch(디스패치)함수를 리턴해준다.
const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn);
이전 포스팅에서 살펴보았던 로그인 유효성 검사 관련 로직을 useReducer를 사용하는 방식으로 바꿔보자. 이메일과 이메일 유효성 검사 통과 여부 상태값, 비밀번호와 비밀번호 유효성 검사 통과 여부 상태값을 객체를 통해 함께 관리하는 방식을 사용한다.
먼저 useReducer를 사용하여 상태를 만들어주자. 이메일, 비밀번호 관련 두 개의 상태를 만들었고, value는 말 그대로 유저가 입력한 이메일, 비밀번호인 string 값, isValid는 유효성 통과 여부에 대한 boolean 값을 가진다.
const [emailState, dispatchEmail] = useReducer(emailReducer, {
value: '',
isValid: null,
});
const [passwordState, dispatchPassword] = useReducer(passwordReducer, {
value: '',
isValid: null,
});
그 후, 함수 밖에서 Reducer 함수를 만들어준다. action 타입은 대문자로 적어주는 것이 컨벤션이라고 한다.
action 타입이 'USER_INPUT' 인 경우, action.val, 즉 입력된 값을 value 값으로 가지고 그 값의 유효성 검사 통과 여부를 isValid 값으로 가지는 객체를 리턴한다.
action 타입이 'INPUT_BLUR' 인 경우, 사용자가 해당 input에 대한 입력을 마쳤을 경우이므로 useState를 사용했을 때와 마찬가지로 실시간으로 업데이트 된 상태값인 state의 value 값을 value값으로 가지고 그 값의 유효성 검사 통과 여부를 isValid 값으로 가지는 객체를 리턴한다.
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 passwordReducer = (state, action) => {
if (action.type === 'USER_INPUT') {
return { value: action.val, isValid: action.val.trim().length > 6 };
}
if (action.type === 'INPUT_BLUR') {
return { value: state.value, isValid: state.value.trim().length > 6 };
}
return { value: '', isValid: false };
};
아래와 같이 필요한 상황에 따라 dispatch를 통해 Reducer 함수에 action을 보낸다. 이렇게 하면 Reducer 함수에서 받은 action의 타입에 따라 상태를 적절히 변경시킨다.
참고로 하단의 코드에서 validateHandler에 val 값이 없는 이유는, validateHandler가 실행 될 때에는 이미 사용자가 입력한 값이 전부 changeHandler를 통해 상태에 저장되어 있으므로 이미 각 state는 최신 값을 가지기 때문에 val 값을 보내는 것이 무의미 하기 때문이다.
const emailChangeHandler = (event) => {
dispatchEmail({ type: 'USER_INPUT', val: event.target.value });
// setFormIsValid(
// event.target.value.includes('@') && passwordState.isValid
// );
};
const passwordChangeHandler = (event) => {
dispatchPassword({ type: 'USER_INPUT', val: event.target.value });
// setFormIsValid(emailState.isValid && event.target.value.trim().length > 6);
};
const validateEmailHandler = () => {
dispatchEmail({ type: 'INPUT_BLUR' });
};
const validatePasswordHandler = () => {
dispatchPassword({ type: 'INPUT_BLUR' });
};
간단하게 useReducer Hook을 살펴보았다. useState를 사용하는 것보다 훨씬 복잡해 보인다. useReducer와 useState를 사용해야할 경우를 어떻게 구분해야할까?
- useState()
- 개별 state 및 데이터들을 다루기에 적합 (간단한 state)
- userReducer()
- state로서의 객체가 있는 경우나 복잡한 state의 경우에 적합
- 연관된 state 조각들로 구성된 state 관련 데이터를 다루는 경우 적합
'온라인 강의(유데미, 인프런 등) > React 완벽 가이드(유데미)' 카테고리의 다른 글
[react & typescript] CRA로 typescript 설정하기(feat. esLint, styled-component) (0) | 2023.02.23 |
---|---|
[react] forwardRef (1) | 2023.02.22 |
[react] context API (0) | 2023.02.22 |
[react] useEffect에서 Clean-up 함수 사용하기 (0) | 2023.02.21 |
[react] 제어 컴포넌트 vs 비제어 컴포넌트 (0) | 2023.02.20 |