기록을 합시다.
[React] react-hook-form과 hookform/error-message 이용하여 비밀번호 변경 form 만들기 본문
[React] react-hook-form과 hookform/error-message 이용하여 비밀번호 변경 form 만들기
울집고양이세마리 2023. 4. 14. 23:53form을 만들다가, 역시 이것도 내가 하기 귀찮으니 사람들이 만들어준 문명의 이기 중에 하나인 react-hook-form을 이용하기로 했다. 자, 일단은 react-hook-form을 깔아주자.
npm install react-hook-form
이 포스트에서는 react-hook-form중에서 사람들이 제일 자주 쓰고 유명한 useForm을 위주로 이야기하겠다.
useForm
Performant, flexible and extensible forms with easy-to-use validation.
react-hook-form.com
useForm의 props들은 form의 기본 세팅을 해주는 것 위주이다. (지금은 쓸 게 없음..)
우리는 useForm의 return props 중에 register를 이용하여 input 값을 validate 할 것이다.
useForm - register
Performant, flexible and extensible forms with easy-to-use validation.
react-hook-form.com
일단은 우리가 써야 하는 register가 있다.
register는 input 값 혹은 select 값을 등록할 때(submit 할 때), validation을 수행해준다.
아래의 이 코드는 그 예시이다.
const passwordRegister = register("password", {
required: { value: true, message: "현재 비밀번호를 입력하세요. " },
});
const newPasswordRegister = register("newPassword", {
required: { value: true, message: "새 비밀번호를 입력하세요. " },
validate: (value, formValues) => {
return (
value != formValues.password || "현재와 다른 비밀번호를 사용하세요."
);
},
});
const newPasswordCheckRegister = register("newPasswordCheck", {
validate: (value, formValues) => {
return value === formValues.newPassword || "새 비밀번호가 틀립니다.";
},
});
register(input에 설정할 id, register 옵션)으로 두 개의 파라미터를 받는다.
register option으로는 위의 코드처럼 validate도 있고, required도 있고 상황에 맞게 문서를 보면서 사용하면 된다.
아래는 주요하게 쓰이는 option들을 가져와봤다.
1. required option(빈칸을 submit 하면 안 될 때 이용)
<input
{...register("test"//input id 적는 곳, 굳이 input에 id='test'라고 적을 필요 없다., {
required: {
value: true //true로 설정하면 submit 하기 전에 input에 value가 있어야 한다는 뜻
message: '에러메시지 적는 곳' //value를 true로 설정했을 경우, value가 없을 때 띄울 에러메시지
}
})}
/>
2. pattern option(보통 이메일 형식 확인할 때 이용)
<input
{...register("test", {
pattern: {
value: /[A-Za-z]{3}/, //정규식 패턴 적는 곳
message: 'error message' //정규식 패턴에 해당하지 않는다면 뜰 에러 메시지
}
})}
/>
3. validate option(회원 가입 할 때, 비밀번호 두 번 써서 확인하거나 할 때 쓰면 유용한듯)
<input
{...register("test", {
validate: value => value === '1' || 'error message' //왼쪽 식이 true가 아니라면 오른쪽의 error message 반환
})}
/>
이렇게 세 개가 자주 쓰이는 듯 하다. 그리고 이것들 외에도 좋아보이는 option들이 꽤 있다.
궁금하신 분들은 문서에 들어가서 보면 될 듯 하다. 예제도 쉽게 설명되어 있어서 바로 사용하기가 쉽다.
return (<input
{...register("test", {
validate: value => value === '1' || 'error message' //왼쪽 식이 true가 아니라면 오른쪽의 error message 반환
})}
/>);
const testRegister = register("test", {
validate: value => value === '1' || 'error message' //왼쪽 식이 true가 아니라면 오른쪽의 error message 반환
});
return (<input
{...testRegister}
/>);
참고로 위와 아래 코드의 결괏값은 똑같다. 옵션들을 리턴문에 다 써주면 읽기 힘들어서 아래와 같은 방법을 사용하는 게 내 기준으로 읽기 편했다.
그러면 이제 register를 통해 validation을 어떻게 사용하는지 알게 되었다.
그러면 validateion을 수행하고 나온 error들은 어떻게 처리할까?
이 때는 hookform/error-message을 사용해준다.
npm install @hookform/error-message
useFormState - ErrorMessage
Performant, flexible and extensible forms with easy-to-use validation.
react-hook-form.com
이것도 문서를 보면 매우 EZ 하다.
아래는 문서에서 제공하는 예제를 조금 수정했다.
설명은 주석으로 달아놨다.
import React from "react";
import { useForm } from "react-hook-form";
import { ErrorMessage } from '@hookform/error-message';
export default function App() {
//useForm의 return props들을 가져와준다.
const { register, formState: { errors }, handleSubmit } = useForm();
//onSubmit은 formData를 받은 후에 수행할 동작을 적는다.
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("singleErrorInput", { required: "This is required." })} />
//errors들을 인자로 받고, 그 중에서 id가 "singleErrorInput"인 곳에서 발생하는 에러 메시지들을 출력해준다.
<ErrorMessage
errors={errors}
name="singleErrorInput"
render={({ message }) => <p>{message}</p>}
/>
<input type="submit" />
</form>
);
}
참고로 handleSubmit은 onSubmit 함수를 인자로 받아주는데, preventdefault를 자동으로 수행 해주고, error가 발생할 때에는 submit 안 해주는 기능이 있다. 마지막으로 onSubmit에는 data를 받은 후에 어떤 동작을 할지 적으면 된다. (서버에 보낸다던지..)
아래는 이 위의 것들을 다 활용하여 짠 코드이다.
import { Card, Button, Input, Spacer } from "@nextui-org/react";
import { useForm } from "react-hook-form";
import { ErrorMessage } from "@hookform/error-message";
export default function ChangePassword({ handleSeletedMenu }) {
const {
register,
formState: { errors },
handleSubmit,
} = useForm();
const onSubmit = (formValues) => {
console.log(formValues);
};
const passwordRegister = register("password", {
required: { value: true, message: "현재 비밀번호를 입력하세요. " },
});
const newPasswordRegister = register("newPassword", {
required: { value: true, message: "새 비밀번호를 입력하세요. " },
validate: (value, formValues) => {
return (
value != formValues.password || "현재와 다른 비밀번호를 사용하세요."
);
},
});
const newPasswordCheckRegister = register("newPasswordCheck", {
validate: (value, formValues) => {
return value === formValues.newPassword || "새 비밀번호가 틀립니다.";
},
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Card.Body>
<Input.Password
{...passwordRegister}
label="현재 비밀번호"
placeholder="현재 비밀번호 입력"
/>
<ErrorMessage
errors={errors}
name="password"
render={({ message }) => <h6>{message}</h6>}
/>
<Spacer />
<Input.Password
{...newPasswordRegister}
label="비밀번호 확인"
placeholder="비밀번호 확인"
/>
<ErrorMessage
errors={errors}
name="newPassword"
render={({ message }) => <h6>{message}</h6>}
/>
<Spacer />
<Input.Password
{...newPasswordCheckRegister}
label="비밀번호 확인"
placeholder="비밀번호 확인"
/>
<ErrorMessage
errors={errors}
name="newPasswordCheck"
render={({ message }) => <h6>{message}</h6>}
/>
</Card.Body>
<Card.Footer>
<Button
color="default"
auto
light
style={{ width: "50%" }}
onPress={() => handleSeletedMenu("menu")}
>
취소
</Button>
<Button color="primary" auto type="submit" style={{ width: "50%" }}>
비밀번호 바꾸기
</Button>
</Card.Footer>
<style jsx>
{`
h6 {
color: red;
font-size: 14px;
font-weight: bold;
margin: 8px;
}
`}
</style>
</form>
);
}
아래는 화면 출력물이다.
진짜 만드는 거 너무 간단해서 눈물이 나올 지경이다.