이번 주차의 요구사항은,
저번 주차에 만들었던 Input Component를 이용해서 로그인 및 회원가입 기능을 완성하는 것이다.
하지만, react-hook-form을 적용하는 것이 심화 요구사항이기 때문에 이를 적용해서 구현해보았다.
요구사항의 세부사항이 많은 관계로 간략하게 정리했다!
- input에서 focus out될 때 빈 값이거나 유효한 값이 아니면 에러메시지를 출력한다.
- 모두 유효한 값이 입력되었을 때 로그인 및 회원가입 시도가 가능하고, api에 POST 요청을 보내 로그인 및 회워가입이 가능하면 folder 페이지로 이동한다.
react-hook-form는 처음 써보는 라이브러리였기 때문에 적용하는 과정과 함께 공식 문서의 내용을 정리해보려고 한다
아직 난 아무것도 모르는 응애입니다😊
react-hook-form 공식 문서
그렇다면 공식 문서에 들어갔을 때 처음으로 나온 예제부터 한 번 뜯어보자..!
예제 코드에 주석으로 내가 이해한 바를 적어봤다
import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
// 사용할 input 태그를 구분하기 위한 타입 (2개의 input을 사용해서 2개인 것)
example: string
exampleRequired: string
// email : string; (이렇게 써주면 됨)
}
export default function App() {
const {
// useForm의 프로퍼티 (사용할)
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<Inputs>()
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
// onSubmit이벤트일 때 실행될 함수
// 여기서의 data는 input 태그의 value가 나온다.
console.log(watch("example")) // watch input value by passing the name of it
return (
<form onSubmit={handleSubmit(onSubmit)}>
//사용할 때는 input 태그 안에 이런 식으로 사용하는 구나
<input defaultValue="test" {...register("example")} />
// 두 번째 매개변수에 들어가는 객체가 조건인 것 같다. 이 부분을 나한테 맞게 바꿔야지
<input {...register("exampleRequired", { required: true })} />
<input type="submit" />
</form>
)
}
여기까지는 이해가 되었고,
그렇다면 내가 원하는 동작인 onBlur 되었을 때 input 값에 따라 에러메시지를 출력하게 하려면 어떻게 해야 할 지 알아봐야겠다.
조건을 어디에 어떻게 넣어야되지?
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("example" , {/** Validation(조건 넣기) **/})} />
<input {...register("email", { required : true })} />
</form>
)
input 태그 안에 위 예제의 예시처럼 넣으면 되는 것 같다.
input의 값을 validation을 할 수 있는 조건이 엄청 많을 텐데, 여기에 들어갈 수 있는 조건이 어떤게 있을까 찾아봤다.
그 내용은 공식문서의 1페이지에
Apply validation
HTML 표준에 맞춰 폼 검증을 쉽게 할 수 있도록 해준다.
- required : 값이 필수로 있어야 하는 것인지
- min : 최소값
- max : 최댓값
- minLength : 최소 길이
- maxLength : 최대 길이
- pattern : 정규식
- validate : 위의 검증에서 확인할 수 없는 요소를 함수로 확인하는 것
- 예시) 비밀번호 입력값과 비밀번호 확인값이 일치하는 지를 검증해야할 때
저런 것들을 검증할 수 있구나..! 그럼 조건도 넣어다고 생각해보면
Error 메시지 출력은 어떻게?
우선 useForm에서 formState 에서 errors 객체를 가지고 오자!
그리고, input 태그 안, register 밖에 에러메시지를 띄울 지 말지에 대한 정보를 저장하는 코드를 추가하면 오류 메시지 출력을 위한 기반은 거의 준비가 된 것이다.
aria-invalid ={errors.password ? "true" : "false"}
이제 오류 메시지를 출력해보자
required 의 경우 true 대신 false일 때 출력될 에러 메시지를 직접 적어줘도 된다.
{ required : "이메일을 입력해주세요" }
하지만, 유효성 검증의 경우에도 그렇게 동작하지는 않기 때문에 value 와 message 를 통해서 코드를 처음 본 사람도 이해할 수 있도록 보다 직관적으로 작성해보자.
import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
email : string;
password : string;
}
export default function App() {
const {
register,
handleSubmit,
formState : { errors }, //에러 상태를 제어하는 state
} = useForm<Inputs>()
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="email">이메일</label>
// input Value가 공백일 때, 이메일 정규식에 부합하지 않을 때 에러가 출력되도록 했다.
<input
id="email"
type="email"
placeholder="이메일을 입력해 주세요."
{...register("email", {
required: {
value: true,
message: "이메일을 입력해 주세요.",
},
pattern: {
value: EMAIL_REGEX,
message: "올바른 이메일 주소가 아닙니다.",
},
})}
aria-invalid={errors.email ? "true" : "false"}
/>
{errors.email <h2>{errors.email.message}</h2>}
<button type="submit">로그인</button>
</form>
)
}
검증 조건에 객체로 value, message를 적어주면 errors 객체의 message로 에러 메시지를 저장하고, value의 조건에 맞지 않으면 aria-invalid의 errors.email이 true로 바뀌고, message에 적은 에러 메시지가 전달되어 조건부 렌더링이 된다.
이제 한 가지만 추가하면 된다.
onBlur일때도 에러 메시지가 출력되어야 한다 !
onSubmit 이외의 이벤트에서도 입력값 검증하기
react-hook-form의 mode
useForm의 매개변수로 mode : 원하는 이벤트 유형 을 추가해주면 동작하게 된다.
prop으로 넘겨줄 수 있는 mode의 종류
- onChange
- onBlur
- onSubmit
- onTouched
- all
* 주의할 점은, mode에 onChange가 들어갈 경우, 다수의 리렌더링이 발생해 성능에 영향을 끼칠 수 있다.
사용 방법 이해를 위해 아주 간결하게 작성한 코드를 마저 완성해보자면 아래와 같다.
import { useForm, SubmitHandler } from "react-hook-form"
type Inputs = {
email : string;
}
export default function App() {
const {
register,
handleSubmit,
formState : { errors }, //에러 상태를 제어하는 state
} = useForm<Inputs>({ mode : "onBlur" })
const onSubmit: SubmitHandler<Inputs> = (data) => console.log(data)
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="email">이메일</label>
// input Value가 공백일 때, 이메일 정규식에 부합하지 않을 때 에러가 출력되도록 했다.
<input
id="email"
type="email"
placeholder="이메일을 입력해 주세요."
{...register("email", {
required: {
value: true,
message: "이메일을 입력해 주세요.",
},
pattern: {
value: EMAIL_REGEX,
message: "올바른 이메일 주소가 아닙니다.",
},
})}
aria-invalid={errors.email ? "true" : "false"}
/>
{errors.email <h2>{errors.email.message}</h2>}
<button type="submit">로그인</button>
</form>
)
}
여기까지 이해했다면, react-hook-form으로 로그인 및 회원가입 페이지를 모두 구현할 수 있을 거라고 생각했다.
하지만 그것은 큰 오산...!!
이 사용법으로는 로그인 및 회원가입 기능을 구현하는데 한계가 있었다.
기본 사용법 이외에 더 필요한 부분이 있었고, 이어서 그 내용도 마저 정리해보자! 💡
서버로 데이터를 요청했을 때, rejected되었다면 다른 에러메시지를 출력해야 함
errors.message에 어떻게 접근할 수 있을까 (에러 메시지 전달을 위해서)
https://react-hook-form.com/docs/useform/seterror
이 질문의 답은 setError 메서드에 있었다.
const {
register,
handleSubmit,
formState: { errors },
setError,
} = useForm<IFormInput>({ mode: "onBlur" });
const handleInputValue: SubmitHandler<IFormInput> = async (data) => {
const inputValue = {
email: data.email,
};
try {
const token = await checkSignin(inputValue);
router.push("/folder");
} catch {
setError("email", {
message: "이메일을 확인해 주세요.",
});
}
};
return(
//...
<S.InputBox
id="email"
type="email"
placeholder="이메일을 입력해 주세요."
{...register("email", {
required: {
value: true,
message: "이메일을 입력해 주세요.",
},
pattern: {
value: EMAIL_REGEX,
message: "올바른 이메일 주소가 아닙니다.",
},
})}
aria-invalid={errors.email ? "true" : "false"}
/>
{errors.email && <S.InputErrorMessage>{errors.email.message}</S.InputErrorMessage>
//...
);
useForm에서 setError 메서드를 추가해주고,
catch문 안에서 위와 같이 사용하면 input 태그 안에서 따로 지정해주지 않아도 에러메시지를 전달할 수 있다.
비밀번호 입력값과 비밀번호 확인 입력값을 비교해서 에러메시지를 출력해야 함
다른 input의 입력값을 어떻게 가지고 올 수 있을까
그 입력값을 통해서 어떻게 에러 메시지를 출력하게 할 수 있을까
https://react-hook-form.com/docs/useform/getvalues
위의 문제에 대한 답은 getValues 메서드와 함께, validation의 validate 조건을 사용하면 된다.
const {
register,
handleSubmit,
formState: { errors },
setError,
getValues,
} = useForm<IFormInput>({ mode: "onBlur" });
const isConfirmPasswordRepeat = (insertPasswordRepeat: string) => {
return getValues("password") === insertPasswordRepeat
? true
: "비밀번호가 일치하지 않아요.";
};
return(
<input
id="email"
type="email"
placeholder="이메일을 입력해 주세요."
{...register("email", {
validate: async (value) => {
const result = await isConfirmPassword({ email: value });
return result;
},
})}
aria-invalid={errors.email ? "true" : "false"}
/>
{errors.email ? (
<S.InputErrorMessage>{errors.email.message}</S.InputErrorMessage>
);
위와 같이 validate에 콜백 함수를 넣은 후, return 값이 true 이거나 false일 때 오류 메시지를 작성하면 원하는 대로 동작하게 할 수 있다.
위의 두 가지 문제 해결하면서 로그인 및 회원가입 기능 구현이 완성되었다~~!~!~!~!~! 와아아아아!! 🎉🎉
처음 사용하는 라이브러리라서 많이 헤맸지만, 끝까지 기능 구현을 해내서 기분이 좋다.
앞으로 새롭게 접하는 라이브러리가 많겠지만, 차근차근 공식 문서를 읽어나가면서 동작 원리와 적용 방법 등을 쌓아나갈 수 있었으면 좋겠다.
그럼 이만~!
다음주에는 모달 리팩토링을 기깔나게 해서 오고 싶네요 ㅎㅅㅎ
'💡뚝딱뚝딱 만들어보자 ~! :) > Linkbrary' 카테고리의 다른 글
[Refactoring] 모듈화 및 추상화를 통한 API함수 개선해보기 (0) | 2024.05.21 |
---|---|
[Refactoring] ContextAPI로 Modal 컴포넌트 개선하기 (0) | 2024.04.10 |
커스텀 훅 도전기 (feat.Intersection Observer) (0) | 2024.04.01 |
40% 부족한 검색 기능 완성 시키기 (0) | 2024.03.24 |