팀프로젝트: Wingle(1.4.5) API 연결 - Auth: 회원가입 input 데이터 관리

윤뿔소·2023년 4월 25일
0

팀프로젝트: Wingle

목록 보기
8/16

전편에 이어서 이메일 확인 인증번호를 받는 기능부터 만들어보겠다.

emailVerify

우선 인증번호를 받고 check 하는 기능을 연결한 버튼에 연결할 API 코드를 먼저 구현해보자.

API 통신

먼저 API 스펙을 보자.

  1. certificationKey: string, 인증번호 key, email을 넣으면 됨
  2. 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을 리코일 아톰에 넣는 걸로 응답 처리를 했다.

쿼리 호출 및 TSX 구현

<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를 나오게끔 했다.

Nickname

닉네임 검증도 비슷하다. 원래 순서가 비밀번호/이름 입력 후 하는건데 같은 리액트쿼리를 사용하여 했기때문에 얘를 먼저 구현해보겠다.

API 통신

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로 보내는 것이 nicknameisVerifiedNickname 2개라 2개를 성공시 리코일에 넣어주는 모습이다.

여기서 특이한 점이 있다. 바로 isCheckedisVerify 상태 2개를 받아서 하는 것이다.

  const [isCheckedNickname, setCheckedNickname] = useState(false);
  const [isVerifiedNickname, setVerifiedNickname] = useState(false);

그 이유는 그다음 TSX 부분 구현하면서 설명하겠다.

쿼리 호출 및 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은 유효성 검사 부분 에러 및 멘트)

위의 설명과 이어서 얘기하자면

  1. isCheckedNickname를 이용해 닉네임이 변하면 상태를 isCheckedNicknamefalse로 만들고, 또 에러멘트를 안보이게 만드는 조건으로 씀.
  2. isVerifiedNickname으로 API 통신 응답을 통해 멘트가 변경되게 설정

그래서 비슷한 checked와 verify 2개를 쓴 것이다. 정리하자면 닉네임이 onChange가 될 때 handleErrorNickName, setVerifiedNickname, setCheckedNickname이 변경돼 초기상태로 돌아가는 것이다.

그렇게 상태를 관리하여 사용자가 어떤 닉네임을 작성하고, 수정하든 자유롭게 되게 만들었다.


다 비슷한 느낌이지만 유효성 검사, 응답 조건 등 디테일하게 달라 감을 익히는데 애를 먹었다. 쨌든 input 관련해서 API 연결하는 건 여기까지가 끝이다.

이게 또 길어져서 다음편에 이어서 input을 쓰겠다. 다음엔 비밀번호/확인/성함 부터 기술 하겠다.

profile
코뿔소처럼 저돌적으로

7개의 댓글

comment-user-thumbnail
2023년 4월 25일

저도 로직을 작성할때 유효성검사가 은근 빡세더라구여 모든 경우의수와 우선순위를 고려해야하니 어려웠습니다. 그리고 인상깊은 점이 네이밍을 잘하시는거 같네요 목적어도 잘써주시는거같아요. 고생하셧습니다!

1개의 답글
comment-user-thumbnail
2023년 4월 30일

하나하나 너무 꼼꼼해서 넘 멋집니당

답글 달기
comment-user-thumbnail
2023년 4월 30일

항상 자세하게 작성해주셔서 많이 배우고 갑니다 !

답글 달기
comment-user-thumbnail
2023년 4월 30일

호오 유효성 검사가 빡세군요ㅠ.. 어렵지만 코드가 깔끔해서 읽기 좋네요!!

1개의 답글
comment-user-thumbnail
2023년 5월 1일

유효성 검사 잘 보고 갑니다!

답글 달기