//src>components>auth>SignInForm.jsx
// (전략)
const [id, setId] = useState("");
const [pw, setPw] = useState("");
const [nickName, setNickName] = useState("");
//(중략)
onChange={(e) => {
setPw(e.target.value);
}}
onChange={(e) => {
setNickName(e.target.value);
}}
onChange={(e) => {
setId(e.target.value);
}}
//(후략)
//src>hooks>useForm.js
const { useState } = require("react");
const useForm = (initialState = {}) => {
//={} 해준건 그냥 기본값 설정임. 실제로는 호출부에서 인자로 받음
const [formState, setFormState] = useState(initialState);
const onChangeHandler = (event) => {
const { name, value } = event.target;
setFormState((prev) => ({ ...prev, [name]: value }));
};
const resetForm = () => {
setFormState(initialState);
};
return { formState, onChangeHandler, resetForm };
};
export default useForm;
//src>pages>Login.jsx
import useForm from "hooks/useForm";
//(중략)
const { formState, onChangeHandler, resetForm } = useForm({
id: "",
password: "",
nickname: "",
});
const { id, password, nickname } = formState;
//(중략)
<Input
name="password"
onChange={onChangeHandler}
value={password}
placeholder="비밀번호 (4~15글자)"
minLength={4}
maxLength={15}
/>
State 통합
내 코드는 id/pw/nickname 에 대하여 각각 하나씩의 state를 만들고 이것을 각 Input 컴포넌트에서 onChange 에 엮어서 제어하고 있다. 이에 반해 모범 코드에서는 id/pw/nickname 세가지 필드를 가진 객체로 state 하나를 관리하고 있다.
커스텀 훅
커스텀 훅을 만들어서 코드를 간결하게 유지하는 것 또한 주목할 만하다. onChangeHandler 함수도 커스텀 훅 내에서 정의하고 이것을 객체에 담아서 리턴해주면 호출부에서 그 함수를 그대로 쓸수 있다는 것은 기억해 두어야 한다. 애초에 호출부에서 객체구조분해 할당으로 커스텀훅으로부터 리턴 받은 것들을 편하게 사용할 수 있게 한 것도 본받을 만하다.
Onchange 핸들러 통합
내 코드에서는 세개의 onChange 핸들러를 사용하고 있는 반면에 모범 코드에서는 onChange 핸들러 하나를 사용하고 있다.
id, pw, nickname 이 각각 다른 필드인데 어떻게 하나의 함수로 이 변화를 처리하는 것일까?
{ ...prev, [name]: value }
그건 이 부분을 보면 알 수 있는데, 변경 되지 않은 필드에 대해서는 ...prev로 그대로 받고 변경되는 함수에 대해서만 값을 갱신할 수 있도록 [name]:value
로 작성되었다. name 은 상태 객체의 필드명인 동시에 Input 태그의 property 이기도 하다. 애초에 처음 코드를 작성할 때부터 이렇게 사용할 의도로 각 Input 태그에 name 프러퍼티를 부여하고 그것과 같은 이름으로 state 객체의 필드명을 지정한 것이다.
참고로 name 은 e.target.value 했던 것과 동일하게 e.target.name 으로 접근할 수 있으며, 여기서도 접근의 용이성을 위해 onChange 핸들러 내에서 const { name, value } = event.target;
이렇게 객체구조분해할당을 하고 있다.