전편에 이어서 이메일 확인 인증번호를 받는 기능부터 만들어보겠다.
우선 인증번호를 받고 check 하는 기능을 연결한 버튼에 연결할 API 코드를 먼저 구현해보자.
먼저 API 스펙을 보자.
certificationKey
: string, 인증번호 key, email을 넣으면 됨certificationCode
: string, 인증번호 (사용자가 입력한 인증번호)이런 식으로 받는다. 이제 post 해보자.
interface EmailCertificationRequest {
email: string;
emailCertification: string;
}
interface EmailCertificationResponse {
status: number;
message: string;
data: {
available?: boolean;
};
}
export const verifyEmailCertification = async ({
email,
emailCertification,
}: EmailCertificationRequest): Promise<boolean> => {
const response = await instance.post<EmailCertificationResponse>("/auth/email/certification", {
certificationKey: email,
certificationCode: emailCertification,
});
return response.data.data.available || false;
};
요청과 응답을 받는 타입과 verifyEmailCertification
를 구현했다. 리턴에 불린데이터인 available
를 리턴하고, 아니면 false
를 리턴하게 만들었다.
즉, 결과물에 따라 true
면 인증 성공으로 상태를 변경해주고, false
면 오류뜨게 만들면 된다.
// 이메일 인증번호 확인
const { mutate: verifyEmail, isLoading: isLoadingVerifyEmail } = useMutation(
() => verifyEmailCertification({ email, emailCertification }),
{
onSuccess: () => {
setErrorEmailCertify(false);
setSignUpFormData((prev) => ({
...prev,
email,
}));
},
onError: (error) => {
setErrorEmailCertify(true);
throw error;
},
}
);
const handleVerifyEmail = useCallback(() => {
if (email === "") {
alert("이메일을 입력해주세요.");
return;
}
verifyEmail();
}, [email, verifyEmail]);
이렇게 만들었다. 전편 email
을 넣어서 상태를 변경시킨 것처럼 isError~
를 통해 성공 및 에러 처리를 한 후, 성공이라면 email
을 리코일 아톰에 넣는 걸로 응답 처리를 했다.
<Text.Body1 color="gray700">인증번호 입력</Text.Body1>
<Margin direction="column" size={8} />
<S.ContentWrapper>
<S.Content>
<S.InputField small={true} error={isErrorEmailCertify}>
<input
name="emailCertification"
value={emailCertification}
type="string"
placeholder="인증번호"
onChange={(e) => {
handleInputData(e);
}}
/>
</S.InputField>
<S.ButtonWrapper small={true} error={isErrorEmailCertify}>
<S.Button onClick={() => handleVerifyEmail()}>인증 확인</S.Button>
</S.ButtonWrapper>
</S.Content>
{isLoadingVerifyEmail ? (
<ErrorMent error={false} errorMent="" ment="인증 확인 중 입니다." />
) : (
<ErrorMent
error={isErrorEmailCertify}
errorMent="인증정보가 일치하지 않습니다."
ment="인증이 완료되었습니다."
/>
)}
</S.ContentWrapper>
emailCertification
이라는 input과 emailCertification
이라는 상태를 넣고 isLoadingVerifyEmail
를 조건으로 나눠 ErrorMent
를 나오게끔 했다.
닉네임 검증도 비슷하다. 원래 순서가 비밀번호/이름 입력 후 하는건데 같은 리액트쿼리를 사용하여 했기때문에 얘를 먼저 구현해보겠다.
export const checkNicknameAvailable = async (nickname: string): Promise<EmailAuthResponse> => {
const response = await instance.post<EmailAuthResponse>("/auth/nickname", { nickname: nickname });
return response.data;
};
nickname
을 파라미터로 받고 바디로 보내고 인증번호완 다르게 data
를 리턴했다. 여기서는 response의 message
를 쓰기때문에 data
자체를 리턴했다.
// 닉네임 중복 확인 기능
const { mutate: CheckNickname } = useMutation(() => checkNicknameAvailable(nickname), {
onSuccess: () => {
setCheckedNickname(true);
setVerifiedNickname(true);
setSignUpFormData((prev) => ({
...prev,
nickname,
isVerifiedNickname,
}));
},
onError: (error) => {
setCheckedNickname(true);
setVerifiedNickname(false);
setSignUpFormData((prev) => ({
...prev,
nickname: "",
isVerifiedNickname,
}));
throw error;
},
});
const handleCheckNickname = useCallback(() => {
if (nickname === "") {
alert("닉네임을 입력해주세요.");
return;
}
CheckNickname();
}, [CheckNickname, nickname]);
signupFormData
로 보내는 것이 nickname
과 isVerifiedNickname
2개라 2개를 성공시 리코일에 넣어주는 모습이다.
여기서 특이한 점이 있다. 바로 isChecked
와 isVerify
상태 2개를 받아서 하는 것이다.
const [isCheckedNickname, setCheckedNickname] = useState(false);
const [isVerifiedNickname, setVerifiedNickname] = useState(false);
그 이유는 그다음 TSX 부분 구현하면서 설명하겠다.
<Text.Body1 color="gray700">닉네임</Text.Body1>
<Margin direction="column" size={8} />
<S.ContentWrapper>
<S.Content>
<S.InputField small={true} error={isErrorNickName}>
<input
name="nickname"
value={nickname}
type="string"
placeholder="희망찬윙그리"
onChange={(e) => {
handleInputData(e);
handleErrorNickName(e);
setVerifiedNickname(false);
setCheckedNickname(false);
}}
/>
</S.InputField>
<S.ButtonWrapper small={true} error={false}>
<S.Button onClick={() => handleCheckNickname()}>중복 확인</S.Button>
</S.ButtonWrapper>
</S.Content>
<ErrorMent
error={isErrorNickName}
errorMent="한글/영어 두글자 이상 10글자 이하로 입력해주세요."
ment=" "
/>
{isCheckedNickname ? (
<ErrorMent
error={!isVerifiedNickname}
errorMent="이미 사용중인 닉네임입니다."
ment="사용가능한 닉네임입니다."
/>
) : null}
(isErrorNickName
은 유효성 검사 부분 에러 및 멘트)
위의 설명과 이어서 얘기하자면
isCheckedNickname
를 이용해 닉네임이 변하면 상태를 isCheckedNickname
를 false
로 만들고, 또 에러멘트를 안보이게 만드는 조건으로 씀.isVerifiedNickname
으로 API 통신 응답을 통해 멘트가 변경되게 설정그래서 비슷한 checked와 verify 2개를 쓴 것이다. 정리하자면 닉네임이 onChange
가 될 때 handleErrorNickName
, setVerifiedNickname
, setCheckedNickname
이 변경돼 초기상태로 돌아가는 것이다.
그렇게 상태를 관리하여 사용자가 어떤 닉네임을 작성하고, 수정하든 자유롭게 되게 만들었다.
다 비슷한 느낌이지만 유효성 검사, 응답 조건 등 디테일하게 달라 감을 익히는데 애를 먹었다. 쨌든 input 관련해서 API 연결하는 건 여기까지가 끝이다.
이게 또 길어져서 다음편에 이어서 input을 쓰겠다. 다음엔 비밀번호/확인/성함 부터 기술 하겠다.
저도 로직을 작성할때 유효성검사가 은근 빡세더라구여 모든 경우의수와 우선순위를 고려해야하니 어려웠습니다. 그리고 인상깊은 점이 네이밍을 잘하시는거 같네요 목적어도 잘써주시는거같아요. 고생하셧습니다!