[TIL] 220916

먼지·2022년 9월 16일
0

TIL

목록 보기
32/57
post-thumbnail

회원가입 유효성 검사

https://rateye.tistory.com/468

유효성 검사하는 거.. 이걸 onChange 함수로 체크해 바로바로 보여줄 수 있는 방식, 중복확인과 가입하기 때 다 체크해줘야 하는데 좋은 방법이 떠오르지 않아서 며칠을 조금씩 수정했는데

함수를 하나 만들어서 value가 바뀔 때마다 확인하고 문구를 보여주려고 했는데 각각의 input 등을 반복문으로 돌려서 inputState value가 한 글자가 바뀔 때마다 validation 함수가 5번씩 호출됐다. 당연한 결과겠지만 바로바로 정규식을 검사할 수 있는 방법이 이것밖에 떠오르지 않았다ㅜㅜ
components/register/SignUp.tsx

function SignUp() {
  ...
  
  const validation = (name: string) => {
    console.log('validation');
    const idRegExp = /^[a-z]+[a-z0-9]{5,19}$/g;
    const pwRegExp = /^(?=.*\d)(?=.*[a-zA-Z])[0-9a-zA-Z]{8,16}$/;
    switch (name) {
      case 'id':
        return id.value
          ? idRegExp.test(id.value)
            ? ''
            : '영문자로 시작하는 영문자 또는 숫자 6~20자 '
          : '';
      case 'pw':
        return pw.value
          ? pwRegExp.test(pw.value)
            ? ''
            : '8 ~ 16자 영문, 숫자 조합'
          : '';
      case 'pwCheck':
        return pwCheck.value
          ? pw.value === pwCheck.value
            ? ''
            : '비밀번호가 일치하지 않습니다.'
          : '';
      default:
        return '';
    }
  };
  
  return (
    <form onSubmit={handleSignUp}>
      {signupInputsData.map(([id, type, title, placeholder]) => (
      	<>
        ...
          <p className="text-red-400">{validation(id)}</p>
        </>
      )}
    </form>
  );    
}

아이디나 닉네임 중복 확인을 할 때 체크

...

const signupInputsData = [
  ['id', 'text', '아이디', '아이디를 입력해주세요.'],
  ['nickname', 'text', '닉네임', '사용하실 닉네임을 입력해주세요.'],
  ['pw', 'password', '비밀번호', '비밀번호를 입력해주세요.'],
  ['pwCheck', 'password', '비밀번호 확인', '비밀번호를 확인합니다.'],
  ['profileImage', 'text', '프로필 사진', '선택된 파일 없음'],
];

//
function SignUp() {
  const [_, setCurrentUser] = useRecoilState(currentUserState);
  const [signupInputs, setSignupInputs] = useState<SignupInputs>({
    id: { value: '', error: '' },
    nickname: { value: '', error: '' },
    pw: { value: '', error: '' },
    pwCheck: { value: '', error: '' },
    profileImage: { value: '', error: '' },
  });
  const { id, nickname, pw, pwCheck, profileImage } = signupInputs;
  const { value: duplicateCheckedId, setValue: setDuplicateCheckedId } =
    useInput('');
  const {
    value: duplicateCheckedNickname,
    setValue: setDuplicateCheckedNickname,
  } = useInput('');
  const { value: fileDataUrl, setValue: setFileDataUrl } = useInput('');

  const setSignupInputsValueOrError = (
    type: 'value' | 'error',
    id: string,
    text: string
  ) => {
    setSignupInputs((prev) => ({
      ...prev,
      [id]: {
        ...prev[id],
        [type]: text,
      },
    }));
  };

  const handleCheckDuplicateIdOrNickname = (type: 'id' | 'nickname') => {
    if (type === 'id') {
      if (!/^[a-z]+[a-z0-9]{3,16}$/g.test(id.value)) {
        setSignupInputsValueOrError(
          'error',
          'id',
          '영문자로 시작하는 영문자 또는 숫자 4~15자'
        );
        return;
      }
      checkDuplicateIdRequest(id.value).then((data) => {
        setDuplicateCheckedId(!data ? id.value : '');
        setSignupInputsValueOrError('error', 'id', '');
        alert(!data ? '사용 가능한 아이디입니다' : '중복된 아이디입니다');
      });
    } else {
      if (nickname.value.length < 2) {
        setSignupInputsValueOrError(
          'error',
          'nickname',
          '닉네임은 2자 이상 입력해 주세요'
        );
        return;
      }
      checkDuplicateNicknameRequest(nickname.value).then((data) => {
        setDuplicateCheckedNickname(!data ? nickname.value : '');
        setSignupInputsValueOrError('error', 'nickname', '');
        alert(!data ? '사용 가능한 닉네임입니다' : '중복된 닉네임입니다');
      });
    }
  };

  ...
  
  return (
    <form onSubmit={handleSignUp}>
      {signupInputsData.map(([id, type, title, placeholder]) => (
        ...
              {(id === 'id' || id === 'nickname') && (
                <button
                  onClick={() => handleCheckDuplicateIdOrNickname(id)}
                >
                  중복확인
                </button>
              )}
          <span className="text-sm tracking-tighter text-red-400">
            {signupInputs[id].error}
          </span>
		...
  );
}

또 중복이 아닐 때 duplicateCheckedNickname & Id state 중복되지 않은 현재 value를 담는데, 만약 중복 체크 후에 값을 변경할 수 있으니 가입하기를 눌러서 폼을 제출할 때 한 번 더 확인해야 한다. 그리고 나머지 input filed 값들도 유효성 검사ㅜ

만약 id input에 'test' 값이 있고 중복 체크를 하면 중복된 값이 아닐 시 duplicateCheckedId state에 'test'가 중복되면 ''이 담기는데 빈 문자열은 falsy 값이므로 !를 붙여서 true가 된다 그래서 true || 중복체크된 값이랑 input 값이 다른지를 체크했다.

  const handleSignUp = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (!duplicateCheckedId || duplicateCheckedId !== id.value) {
      alert('아이디 중복 확인을 해주세요');
      return;
    }
    if (
      !duplicateCheckedNickname ||
      duplicateCheckedNickname !== nickname.value
    ) {
      alert('닉네임 중복 확인을 해주세요');
      return;
    }
    if (!/^(?=.*\d)(?=.*[a-zA-Z])[0-9a-zA-Z]{5,16}$/.test(pw.value)) {
      setSignupInputsValueOrError('error', 'pw', '6~16자 영문, 숫자 조합');
      return;
    } else {
      setSignupInputsValueOrError('error', 'pw', '');
    }
    if (pw.value !== pwCheck.value) {
      alert('비밀번호가 일치하지 않습니다');
      return;
    }
    signupRequest({
      username: id.value,
      nickname: nickname.value,
      password: pw.value,
      userImageUrl: profileImage.value || defaultProfileImage,
      socialType: 'GENERAL',
    })
      .then((data) => {
        setCurrentUser(data);
        goToHome();
      })
      .catch((err) => {
        console.log('signup error', err);
      });
  };
    // 가입요청로직

이렇게 하면 필드가 공백인지도 걸러진당

가입 시 바로 로긴

별거 없는데 시간 엄청 날렸다.. 내가 javascript regExp랑 정규식을 몰랐고 정리가 안 된 채로 계속 수정하면서 개발해가지고 🤕 텀블벅 사이트처럼 input value state가 변경될 때마다 표시하고 싶엇는데 머가 계속 안 됐고 어쨌든 앞으로 조금 신경써야 하는 로직은 작게라도 계획을 세워놓고 개발해야겠다

profile
꾸준히 자유롭게 즐겁게

0개의 댓글