코딩을 하다보면 반복적으로 발생하는 로직들이 있다.
예를 들어서 input을 관리하는 코드 같은 경우, 입력하는 텍스트의 name과 value값을 가져오고 그 값들을 통해서 input의 상태를 업데이트 하는것 같은 것도 자주 사용한다.
const onChange = (e) => {
const {name, value} = e.target;
setInputs({...inputs, [name]:value});
이런 경우에는 customHook을 만들어서 간편하게 사용할수 있다.
예를 들어서 useInputs
라는 파일을 만든다고 해보자.
import {useState, useCallback} from 'react';
// initialForm : 해당 인풋에서 관리하는 초기값
function useInputs(initialForm) {
const [form ,setFrom] = useState(initialForm);
const onChange = useCallback(e => {
const {name, value } = e.target;
setFrom(form =>({...form, [name] : value }));
}, [])
const reset = useCallback(() => setFrom(initialForm),[initialForm]);
return [form, onChange, reset];
}
export default useInputs;
initailForm 이라는 초기값을 받아와서, 해당 form의 상태를 조회하고 싶으면 form을 호출하고 input의 내용변경을 원한다면 onChange를 호출하며, input의 내용을 초기화 하고싶으면 reset을 호출한다.
이제 제작한 customHook을 App.js로 옮겨서 사용해보자.
onChange을 만들었으므로 리덕스에서의 'CHANGE_INPUT'은 필요없다. 또한 initialState
내부에서 배열의 초기값을 나타내는 inputs
또한 필요없다.
비구조화 할당으로 변수를 꺼내오는것도 제거한다.
hook을 작성한다.
const [form, onChange, reset] = useInputs({
username: '',
email: '',
});
username과 email을 form에서 추출한다.
const { username, email} = form;
reset의 경우 onCreate안에 호출한다.
const onCreate = useCallback (() => {
dispatch({
type:'CREATE_USER',
user: {
id: nextId.current,
username,
email,
}
});
nextId.current += 1;
reset();
},[username, email, reset])
이렇게 변경을 하고 난 뒤에도 제대로 작동한다.
그럼 만약에 useInputs를 useState 대신에 useReducer를 사용하면 어떻게 할까?
function reducer(state, action){
switch(action.type){
case 'CHANGE':
return{
...state,
[action.name] : action.value
}
case 'RESET':
return Object.keys(state).reduce((acc,current) => {
acc[current] =''
return acc
},{});
default:
throw new Error('Unhandled action');
}
}
reset의 경우 리듀서에게 전송하는 값은 없고, type은 RESET이다.
function useInputs(initialForm) {
const [form, dispatch] = useReducer(reducer, initialForm)
const onChange = useCallback(e => {
const {name, value} = e.target
dispatch({
type: 'CHANGE',
name,
value
})
}, [])
const reset = useCallback(() =>
dispatch({
type:'RESET'
}),[]);
return [form, onChange, reset];
}