모달창에서 피파온라인 닉네임을 입력받을 때 2가지의 경우에 대한 유효성 검사를 한다
이 과정을 try catch를 통한 에러처리로 진행한다
AskNickNameModal.tsx
import React, { useState } from 'react';
import { useModalAPI } from '../../Context/Modal/ModalContext';
import { authService } from '../../../firebase';
import { collection, addDoc, getDocs, updateDoc, doc } from 'firebase/firestore';
import { dbService } from '../../../firebase';
import FIFAData from '../../Services/FifaData';
import { useUserObjAPI } from '../../Context/UserObj/UserObjContext';
import { getErrorMessage, getErrorName } from '../../utils/getErrorMessage';
const AskNickNameModal = () => {
const [nickNameInput, setNickNameInput] = useState('');
const { closeModal } = useModalAPI()!;
const { setUserObj } = useUserObjAPI()!;
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setNickNameInput(value);
};
const closeModalAndGotoHome = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const getData = async () => {
try {
**// 해당 닉네임이 이미 이 웹에서 사용되고 있는지 확인
// 만약 이미 DB에 존재한다면 error를 throw**
const dbInfo = await getDocs(collection(dbService, 'userInfo'));
dbInfo.forEach((i) => {
if (i.data().nickname === nickNameInput) {
throw new SyntaxError('이미 존재하는 계정입니다');
}
});
**// 해당 닉네임이 피파온라인 계정에 존재하지 않는다면
// 아래의 api호출에서 404 axios error를 발생**
const fifa = new FIFAData();
const result = await fifa.getUserId(nickNameInput);
let obj = {
googleUID: String(authService.currentUser?.uid),
FIFAOnlineAccessId: result.accessId,
level: result.level as unknown as number,
nickname: result.nickname,
};
await addDoc(collection(dbService, 'userInfo'), {
...obj,
});
setUserObj(obj);
closeModal();
alert('등록이 완료되었습니다!');
} catch (error) {
**// 에러 이름과 에러 메세지를 유틸 함수로부터 받아옴
// 에러 이름을 기반으로 서로 다른 경고 메세치 출력**
const message = getErrorMessage(error);
const errorName = getErrorName(error);
if (errorName === 'AxiosError') {
alert('해당 계정이 존재하지 않습니다. 다시 한번 입력 해 주세요!');
}
if (errorName === 'SyntaxError') {
alert(message);
}
setNickNameInput('');
}
};
getData();
};
return (
<div>
실제 피파온라인 계정과 연동이 필요합니다 피파온라인에서 사용하고 계시는 닉네임을 입력 해 주세요!
<form onSubmit={closeModalAndGotoHome}>
<input onChange={onChange} value={nickNameInput} />
<input type="submit" value="확인 후 닫기" />
</form>
</div>
);
};
export default AskNickNameModal;
위의 과정에서 try 안에서 2개의 조건을 검사하고 만약 하나라도 걸리는 게 있다면
바로 catch로 넘어가서 경고창을 띄우고 ,
입력창 상태를 빈 문자열로 상태 업데이트를 진행해서
화면을 다시 리렌더링 시켜서 재입력을 요구하는 방식이다
여기서 axios error의 경우 자동으로 catch로 이동하지만
이미 중복된 닉네임이 DB에 존재하는 경우 명시적으로 에러를 throw해줘야 한다
await 다음줄에 if (!result) { throw new Error ()} 이런 방식으로 반환 값에 대해 확인을 하면서 에러를 잡는 것 자체가 불가능하다
애초에 await자체에서 에러가 발생하면 바로 catch로 넘어가므로 나머지 로직은 실행조차 안 되므로 반환값을 확인조차 못 하는 것이다
위의 로직을 보다 보면
// 에러 이름과 에러 메세지를 유틸 함수로부터 받아옴
// 에러 이름을 기반으로 서로 다른 경고 메세치 출력
const message = getErrorMessage(error);
const errorName = getErrorName(error);
이러한 부분을 볼 수 있다
주석에 기재 했듯이 , 에러 이름과 에러 메세지를 기존 JS방식처럼 에러객체로부터
받아오는 것이 아니라 별도의 로직을 통해 반환받는 것이다
JS에서는 catch문에서 인자로 전달받는 error에 대해 아무런 타입이 필요가 없었지만
TypeScript는 error 의 타입을 unknown을 기본값으로 갖기 때문에
TS에서는 타입 지정이 필요하다
그러므로 아래와 같이 일반 JS처럼 진행하게 된다면 에러가 발생한다
let json = '{ "age": 30 }';
try {
let user = JSON.parse(json);
if (!user.name) {
throw new SyntaxError('name 프로퍼티가 존재하지 않습니다');
}
console.log(json); // 이 부분은 실행 x
} catch (error) {
console.log(error.message); // Error
// ('e'은(는) 'unknown' 형식입니다.)
}
TS에서 error의 타입이 unknown인 이유는
throw 된 값은 에러가 아닌 아무 타입이나 던져질 수 있기 때문이다
실제로 JS에서도 아래와 같이 에러가 아닌 것들도 throw가 가능하다
throw "What the!?";
throw 7;
throw { wut: "is this" };
throw null;
throw new Promise(() => {});
throw undefined;
let json = '{ "age": 30 }';
try {
let user = JSON.parse(json);
if (!user.name) {
throw new Error('name 프로퍼티가 존재하지 않습니다');
}
console.log(json); // 이 부분은 실행 x
} catch (error) {
**let message;
if (error instanceof Error) message = error.message;
else message = String(error);**
console.log(message);
}
만약 error가 실제로 Error 객체가 아니라면
에러를 stringify 하여 어느 단서라도 문자열로 출력하도록 한 것이다
이 로직을 모든 catch 블록에서 사용할 수 있는 유틸 함수로도
만들어줄 수 있다
function getErrorMessage(error: unknown) {
if (error instanceof Error) return error.message;
return String(error);
}
let json = '{ "age": 30 }';
try {
let user = JSON.parse(json);
if (!user.name) {
throw new Error('name 프로퍼티가 존재하지 않습니다');
}
console.log(json); // 이 부분은 실행 x
} catch (error) {
console.log(**getErrorMessage(error)**);
}
출처 :