useQuery의 Error 리턴 데이터

라모스·2024년 1월 12일
0

삽질.log

목록 보기
12/12
post-thumbnail
post-custom-banner

개발환경

  • TypeScript + React
  • React-Query v5, Axios, Ant Design

문제 상황

위 사진의 빨간줄 표시가 되어있는 Ant Design의 브레드크럼 컴포넌트에 projectName을 동기화 시켜주기 위한 과정에서 useQuery의 리턴 값 중 refetch() 함수를 사용하여 처리하고 있었다.

프로젝트 조회 useQuery는 무작정 실행되는 게 아니라 특정 조건에서만 실행되도록, enabled 옵션을 false로 두었고 해당 조건은 다음과 같다.

  • 페이지 렌더링 시 브레드크럼 내에 데이터를 넣어주기 위해 query를 refetch 한 결과로 넣어준다.
  • 수정 버튼 클릭 시 브레드크럼 동기화를 위해 refetch를 한다.

만약 프로젝트를 조회 시 서버에서 내려주는 응답이 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에선 해당 옵션이 제거되어 편안하게 에러처리를 할 수 없는 상황이다.

TO-BE

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}`);
  }
};

좀 깔끔해진 것 같다.

profile
Step by step goes a long way.
post-custom-banner

0개의 댓글