위 사진의 빨간줄 표시가 되어있는 Ant Design의 브레드크럼 컴포넌트에 projectName
을 동기화 시켜주기 위한 과정에서 useQuery
의 리턴 값 중 refetch()
함수를 사용하여 처리하고 있었다.
프로젝트 조회 useQuery는 무작정 실행되는 게 아니라 특정 조건에서만 실행되도록, enabled
옵션을 false
로 두었고 해당 조건은 다음과 같다.
만약 프로젝트를 조회 시 서버에서 내려주는 응답이 404나 다른 4xx, 5xx 발생 시 예외처리가 필요한 상황에 놓여있었다.
axios 공통 에러 인터셉터에서 왠만한 에러를 처리하고 있지만, 404 페이지로 리다이렉트 처리를 무작정 해당 인터셉터에 추가하기엔 팀원들의 task feature에 영향이 갈 것 같았다.
그래서 우선 1차로 아래와 같이 에러를 처리했다.
// 프로젝트 가져오기
const projectInfo = useQueryGetProject(
{
projectNo: projectNo ?? '',
},
false
);
// ... (중략)
/** 브래드크럼에 projectName을 넣어주기 위해 데이터를 요청 */
const fetchData = async () => {
handleSetLoadingBreadCrumb();
try {
const response = await projectInfo.refetch();
// 프로젝트 조회 시 존재하지 않는 경우, 404 페이지로 리다이렉트
if (response.isError) {
navigate('/404');
}
if (response.data) {
handleSetBreadCrumb(response.data.projectName);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(`Error: ${e}`);
}
};
useQuery에는 isError
라는 해당 조회 쿼리의 에러 여부를 판별할 수 있는 리턴값이 존재하는데 단순히 boolean 타입인 이를 기반으로 에러를 판단하기엔 무리수가 아닌가 싶다. 왜냐하면 서버에서 내려오는 응답이 404가 확실한지 알 수 없고 404 이외의 에러 발생 시 무조건 404 페이지로 리다이렉트 처리라는게 말이 안된다.
기존 React-Query v4에선 useQuery에 대해 onError
옵션을 제공했지만, 우리 서비스에서 사용하는 v5에선 해당 옵션이 제거되어 편안하게 에러처리를 할 수 없는 상황이다.
const {
data,
error,
status,
fetchStatus,
isLoading,
isFetching,
isError,
refetch,
// ...
} = useQuery({
queryKey: ["super-heroes"],
queryFn: getAllSuperHero,
});
useQuery의 리턴 데이터 중 error라는 것이 있는데, 이를 활용할 수 있음을 미처 생각하지 못했던 것 같다.
const fetchData = async () => {
handleSetLoadingBreadCrumb();
try {
const response = await projectInfo.refetch();
// 프로젝트 조회 시 존재하지 않는 경우, 404 페이지로 리다이렉트
if (response.error?.response.status === HTTP_STATUS_NOT_FOUND) {
navigate('/404');
}
if (response.data) {
handleSetBreadCrumb(response.data.projectName);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(`Error: ${e}`);
}
};
이게 실행은 되지만, VSCode에서 typescript 컴파일 옵션이 내뿜는 빨간줄이 굉장히 거슬린다.
또한, ?
연산자로 nullable함을 나타내지만 이 역시도 한계가 있다.
하지만, 이 에러 객체는 AxiosError
의 타입이기에 타입 단언을 넣어주면 해결할 수 있다.
const fetchData = async () => {
handleSetLoadingBreadCrumb();
try {
const response = await projectInfo.refetch();
// 프로젝트 조회 시 존재하지 않는 경우, 404 페이지로 리다이렉트
if ((response.error as AxiosError)?.response?.status === HTTP_STATUS_NOT_FOUND) {
navigate('/404');
}
if (response.data) {
handleSetBreadCrumb(response.data.projectName);
}
} catch (e) {
// eslint-disable-next-line no-console
console.log(`Error: ${e}`);
}
};
좀 깔끔해진 것 같다.