* useReducer()
useState의 대체 함수로, (state, action) => newState의 형태로 reducer를 받고
dispatch 메서드와 짝의 형태로 현재 state를 반환한다.
Hooks API Reference – React
A JavaScript library for building user interfaces
ko.reactjs.org
useReducer는 내장된 훅으로 state관리를 도와준다.(=useState와 기능이 유사하지만, 더 많은 기능이 있음)
그래서 더 복잡한 state에 특히 유용하다.
여러 state들이 함께 속해 있는 경우 (복잡한 state) - 여러 state가 함께 바뀌거나, 서로 관련되어 있는 경우
useState나 거기에서 얻은 state는 사용 및 관리가 어려워지거나 오류가 발생하기 쉽다.
더 강력한 useState를 사용하고 싶다면 useReducer를 대신해서 사용할 수있다.
더 강력하다 != 더 좋다, 꼭 필요한 곳에서만 사용하고 대부분의 경우에는 useState를 사용
함께 속하는 state들이 있는 경우 useReducer를 사용하기 딱 좋다.
1) 입력된 값이 있고 - 그 값의 유효성이 있는 경우
2) 다른 state에 의존하여 state를 업데이트하는 경우
1과 2가 함께하는 경우에 하나의 state 내에서 객체로 관리하면 useReducer를 사용하지 않아도 괜찮다.
다만, 객체가 값과 유효성 두가지가 아니라 더 복잡한 state들의 집합체라면 useReducer를 사용하는 것을 권장.
const [state, dispatchFn] = useReducer(reducerFn, initialState, initFn);
useReducer는 useState처럼 항상 두개의 값이 있는 배열을 반환한다.
1) state: 최신 state 스냅샷
2) dispatchFn: state 스냅샷을 업데이트 해줄 수 있는 함수(새로운 state값을 설정하는 대신 액션을 dispatch한다.)
3) reducerFn(리듀서함수): dispatchFn에서 dispatch된 액션은 useReducer의 첫번째 인수인 reducerFn이 소비한다. 즉, 최신 state 스냅샷을 자동으로 가져오는 함수. 또한, 새로 업데이트된 state를 반환한다.(useState의 함수와 비슷)
(리액트는 새 액션이 dispatch될 때 마다 리듀서 함수를 호출한다. > 리액트가 관리하는 최신의 state 스냅샷을 가져온다. > 리듀서 함수를 실행시키는 dispatch된 액션을 가져온다.)
4) initialState: 초기 state
5) initFn: 초기 함수
useReducer는 useState와 함께 사용해주면 더 유효한 효과를 낼 수 있다.
//컴포넌트 바깥에 Reducer함수를 선언했는데, 이는 리듀서 함수 내부에서는 컴포넌트 함수 내에서 만들어진 어떤 데이터도 필요하지 않기 때문이다.
//컴포넌트 내에 만들어진 어떤 데이터와도 상호작용하지 않기 때문에 컴포넌트 바깥에서 선언해도 괜찮다.
//action으로 디스패치하는 것은 객체이다.
const emailReducer = (state, action) => {
if(action.type === 'USER_INPUT'){
return {value:action.val, isValid:action.val.includes('@')};
}
//최신 값을 가져오기 위해서는 state.value사용하면 된다.
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};
}
const [emailState, dispatchEmail ] = useReducer(emailReducer,{
value: '',
isValid: undefined,//또는 null로 설정하면 invalid로 처리되지 않는다.
});
const [passwordState, dispatchPassword] = useReducer(passwordReducer, {
value: '',
isValid: undefined,
})
//객체 디스트럭처링 구문(별칭할당)
const { isValid:emailIsValid } = emailState;
const { isValid:passwordIsValid} = passwordState;
useEffect(()=>{
//setTimeout함수를 사용하는 이유는, 입력이 들어올 때 마다 상태를 업데이트 해주기 때문에
//이를 방지하기 위해 사용자의 입력이 일정시간 없을 때, 유효한지를 검사해주기 위함임.
const identifier = setTimeout(()=>{
console.log('Checking from validity!');
setFormIsValid(
emailIsValid && passwordIsValid
);
},500);
//useEffect가 다음 번에 함수를 실행하기 전에 클린업 프로세스로 실행된다.
// 모든 사이드이펙트 함수가 실행되기 전, 컴포넌트가 제거되기 전,
return () => {
console.log('CLEANUP');
//새로운 타이머를 설정하기 전 마지막 타이어를 지우는 clearTimeout
clearTimeout(identifier);
};
},[emailIsValid, passwordIsValid]);
객체 디스트럭처링을 사용해 isValid를 불러오기 위한 변수명을 지정해준다.
매번 타이핑 될 때마다 유효성 검사를 하는 것은 불필요하기 때문에, 유효한 경우에는 유효성 검사를 하지 않게 하려고 한다.
이 경우 state가 바뀔때 마다 검사를 하게 되니, 디스트럭처링을 사용해 유효한지 확인하는 경우에만 useEffect가 실행되게 한다면, 더욱 효과적.
* useState() vs useReducer()
useState를 사용하면 너무 번거로운 경우 useReducer를 사용한다.(너무 많은 일들을 처리해야 하는 경우)
관련 state 스냅샷들이 서로 독립적이고 같이 업데이트가 안된다면 useReducer사용
useState
- state관리 툴
- 개별 state 및 데이터 다루기 적합
- 간단한 state에 적합
- state가 몇 종류 안될 때
- state로서의 객체가 존재하지 않을 때
ex) 두 개의 서로 다른 값을 전환하기만 하는 단순한 state가 있는 경우
useReducer
- state로서의 객체가 존재할 때, 혹은 복잡한 state를 보유하고 있을 때 리듀서함수 사용(컴포넌트 바깥에 정의 가능)
- 연관된 state조각들로 구성된 관련 데이터를 다루는 경우(ex. 폼 input state가 있는 경우)
- 더 복잡한 state가 존재한 경우나, state하나를 변경하는 여러 다른 액션이 존재할 경우
'FE·Client > React' 카테고리의 다른 글
React Hook 규칙, Forward Refs, useImperativeHandle(focus와 scroll) (0) | 2023.01.29 |
---|---|
[React] sh: react-scripts: command not found에러 (0) | 2023.01.29 |
[React] sideEffect() 와 useEffect() (0) | 2023.01.17 |
[React] Portals, Ref, uncontrolled component (0) | 2023.01.11 |
[React] 리액트 컴포넌트 스타일링, styled-components, 미디어쿼리, CSS 모듈 (0) | 2023.01.09 |