React와 axios로 회원가입 기능을 구현하고 있었다.
명세에 따르면 해당 사용자 전화번호가 이미 존재하는 경우 회원가입을 할 수 없다. 그러나 validation을 위한 api는 별도로 존재하지 않았다. (중복 ID를 확인하는 api는 존재해서 ID는 submit 이전에 걸러낼 수 있었다.) 때문에 submit을 할 때 사용자 전화번호가 이미 존재하는 경우와 존재하지 않는 경우에 대한 컨트롤이 필요했다.
const [signupForm, setSignupForm] = useState({
username: '',
password: '',
password2: '',
phone_number: '',
name: '',
});
const [phoneNumberErr, setPhoneNumberErr] = useState('');
const [phoneNumberIsValid, setPhoneNumberIsValid] = useState(false);
const inputChangeHandler = (e) => {
const { name, value } = e.target;
setSignupForm({
...signupForm,
[name]: value,
});
};
const phoneNumberHandler = () => {
const regExp = /^(01[016789]{1})-?[0-9]{3,4}-?[0-9]{4}$/;
if (!signupForm.phone_number) {
setPhoneNumberErr('휴대폰번호는 필수 항목입니다.');
setPhoneNumberIsValid(false);
} else if (signupForm.phone_number.length > 11) {
setPhoneNumberErr('휴대폰번호는 11자리 이하여야 합니다.');
setPhoneNumberIsValid(false);
} else if (!regExp.test(signupForm.phone_number)) {
setPhoneNumberErr(
'핸드폰 번호는 01*으로 시작하는 11자리 숫자여야 합니다.'
);
setPhoneNumberIsValid(false);
} else {
setPhoneNumberErr('');
setPhoneNumberIsValid(true);
}
};
useEffect(() => {
setPhoneNumberErr();
}, [signupForm.phone_number]);
const signupHandler = async (userData) => {
try {
const res = await postSignup(userData);
console.log(res);
} catch (err) {
if (err.response) {
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
} else {
console.log(`Error: ${err.message}`);
}
}
};
const submitHandler = (e) => {
e.preventDefault();
const userData = {
username: signupForm.username,
password: signupForm.password,
password2: signupForm.password2,
phone_number: signupForm.phone_number,
name: signupForm.name,
};
if (
usernameIsValid &&
pwIsValid &&
pwCheckIsValid &&
nameIsValid &&
phoneNumberIsValid
) {
signupHandler(userData);
alert('환영합니다!');
navigate('/login');
}
};
...
<ContInputForm onSubmit={submitHandler}>
<div>
<Input
label='휴대폰번호'
type='text'
name='phone_number'
placeholder='휴대폰 번호를 입력해주세요.'
min='11'
defaultValue={signupForm.phone_number}
onChange={inputChangeHandler}
onBlur={phoneNumberHandler}
message={phoneNumberErr}
/>
</div>
<Button
disabled={
!signupForm.username ||
!signupForm.password ||
!signupForm.password2 ||
!signupForm.name ||
!signupForm.phone_number
}
>
{'오픈 마켓 시작하기'}
</Button>
</ContInputForm>
phoneNumberHandler를 통해 01*으로 시작하는 11자리 숫자를 올바르게 입력했다면, phoneNumberIsValid은 true이다.
submitHandler에서 signupHandler를 작동시켰을 때 에러가 뜨더라도(해당 사용자 전화번호가 중복인 경우) phoneNumberIsValid가 true였기 때문에 회원가입이 정상적으로 이루어지지 않았음에도 '환영합니다!'와 함께 로그인 화면으로 전환되었다.
이전에 비슷한 문제 상황에서 useState를 사용했던 게 떠올라 이번에도 useState를 이용해 문제를 해결하기로 했다.
전화번호 validation api가 없는 관계로 불가피하게 signupHandler 에러 부분에서 submit을 컨트롤해보기로 했다.
const [signupForm, setSignupForm] = useState({
username: '',
password: '',
password2: '',
phone_number: '',
name: '',
});
const [phoneNumberErr, setPhoneNumberErr] = useState('');
const [phoneNumberIsValid, setPhoneNumberIsValid] = useState(false);
// submit을 제출할 수 있는 상태(중복 전화번호 여부)를 구분하는 useState를 추가했다.
const [submit, setSubmit] = useState(false);
const inputChangeHandler = (e) => {
const { name, value } = e.target;
setSignupForm({
...signupForm,
[name]: value,
});
};
const phoneNumberHandler = () => {
const regExp = /^(01[016789]{1})-?[0-9]{3,4}-?[0-9]{4}$/;
if (!signupForm.phone_number) {
setPhoneNumberErr('휴대폰번호는 필수 항목입니다.');
setPhoneNumberIsValid(false);
} else if (signupForm.phone_number.length > 11) {
setPhoneNumberErr('휴대폰번호는 11자리 이하여야 합니다.');
setPhoneNumberIsValid(false);
} else if (!regExp.test(signupForm.phone_number)) {
setPhoneNumberErr(
'핸드폰 번호는 01*으로 시작하는 11자리 숫자여야 합니다.'
);
setPhoneNumberIsValid(false);
} else {
setPhoneNumberErr('');
setPhoneNumberIsValid(true);
}
};
useEffect(() => {
setPhoneNumberErr();
}, [signupForm.phone_number]);
const signupHandler = async (userData) => {
try {
// res가 성공하는 경우 setSubmit(true) 값을 줬다.
const res = await postSignup(userData);
setSubmit(true);
} catch (err) {
// 에러 메세지로 '해당 사용자 전화번호는 이미 존재합니다.'가 뜨는 경우 setSubmit(false) 값을 줬다.
if (err.response) {
console.log(err.response.data);
if (
err.response.data.phone_number[0] ===
'해당 사용자 전화번호는 이미 존재합니다.'
) {
setPhoneNumberErr('해당 사용자 전화번호는 이미 존재합니다.');
setSubmit(false);
}
console.log(err.response.status);
console.log(err.response.headers);
} else {
console.log(`Error: ${err.message}`);
}
}
};
const submitHandler = (e) => {
e.preventDefault();
const userData = {
username: signupForm.username,
password: signupForm.password,
password2: signupForm.password2,
phone_number: signupForm.phone_number,
name: signupForm.name,
};
if (
usernameIsValid &&
pwIsValid &&
pwCheckIsValid &&
nameIsValid &&
phoneNumberIsValid
) {
signupHandler(userData);
}
};
// useEffect로 submit 값이 바뀔 때마다 확인하고, 중복 번호가 아니어서 submit을 해도 될 때(true)만 정상적으로 로그인할 수 있으며 로그인 화면으로 전환될 수 있도록 했다.
useEffect(() => {
setSubmit();
if (submit) {
alert('환영합니다!');
navigate('/login');
}
}, [submit]);
...
<ContInputForm onSubmit={submitHandler}>
<div>
<Input
label='휴대폰번호'
type='text'
name='phone_number'
placeholder='휴대폰 번호를 입력해주세요.'
min='11'
defaultValue={signupForm.phone_number}
onChange={inputChangeHandler}
onBlur={phoneNumberHandler}
message={phoneNumberErr}
/>
</div>
<Button
disabled={
!signupForm.username ||
!signupForm.password ||
!signupForm.password2 ||
!signupForm.name ||
!signupForm.phone_number
}
>
{'오픈 마켓 시작하기'}
</Button>
</ContInputForm>
문제 없이 회원가입 완료!
로그인 페이지에서도 submit을 제출할 때 회원정보가 없는 경우에 비슷한 문제가 있었는데, 이 방법을 통해 문제를 해결했다.
다른 문제 상황에 직면했을 때 이전에 익힌 useEffect를 바로 적용해서 해결할 수 있게 된 것이 뿌듯했다.