[다담다] 우당탕탕 리액트 쿼리 오류 수습기 - 1

한낱·2023년 9월 21일
0
post-thumbnail

서론

오늘 우연찮게 진행중인 프로젝트에서 오류를 발견했다.
현재 우리 프로젝트의 가장 열혈 사용자가 본인이다보니 이미 프로젝트에 저장된 스크랩이 꽤 있다. 그래서 여태껏 스크랩 추가, 삭제가 정상적으로 동작한다고 굳게 믿고 있었는데...!
오늘 다른 팀원의 계정으로 스크랩을 추가/삭제해보다가 스크랩이 하나도 없는 상태에서 스크랩을 추가하거나 한 개 있는 스크랩이 삭제되면 오류가 발생하는 것을 깨달았다.

문제점 파악

  1. 스크랩의 유무가 문제
    스크랩 개수가 0개에서 1개로 변경될 때 / 1개에서 0개로 변경될 때 문제가 발생한다. 즉, 스크랩의 존재 여부 자체가 바뀌면 문제가 발생한다. 현재 서비스에서 스크랩이 하나도 없는 경우와 스크랩이 존재하는 경우 서로 다른 템플릿을 보이도록 설정해두었으므로, 그 부분이 문제일 것이라고 생각했다.
  2. console 오류 메시지 파악
    공교롭게도 console에 떴던 오류 메시지는 최근에 해결했던 오류 메시지였다. 스크랩 페이지에서 특정 스크랩에 대한 설명을 보이기 위해 스크랩 목록 조회 후 제일 첫 번째 스크랩을 선택된 상태로 만드는 과정을 추가해두었다. 해당 오류 메시지는 아직 스크랩 목록을 전달받지 못해 첫번째 스크랩이 '선택'되지 않았는데 먼저 첫 번째 스크랩에 대한 렌더링을 진행하려 할 때 발생했다.
  3. 네트워크 및 리액트 쿼리 DevTools
    해당 페이지에서 필요로 하는 요청과 응답이 제대로 이루어지고 있는지 확인해보기 위해 개발자 도구 네트워크 탭을 열어보니 관련 API를 요청하고 있지 않았고, 리액트 쿼리 DevTools에서는 조회했던 API를 refetch하지 않고 있음을 알 수 있었다.

코드

export const useDeleteScrap = () => {
    const queryClient = useQueryClient();
    return useMutation(fetchDeleteScrap, {
        onSuccess: () => {
            queryClient.invalidateQueries(['scraps']);
            useDefaultSnackbar('스크랩이 삭제되었습니다.', 'success');
        },
        onError: (error) => {
            Sentry.captureException(error);
            useDefaultSnackbar('스크랩 삭제에 실패하였습니다.', 'error');
        },
        useErrorBoundary: false,
    });
}

이는 수정하기 전 코드인데, 스크랩 삭제를 성공하면 invalidateQueries를 통해 스크랩 목록을 다시 조회하도록 한다. 추가에도 동일한 코드가 삽입되어 있다.

스크랩이 하나 존재하는 템플릿에서 해당 스크랩을 삭제하면 스크랩이 없는 템플릿으로 변경되어야 한다. 하지만, 현재 스크랩 페이지 코드는 스크랩 개수를 요청하여 0개일 때는 스크랩 없는 템플릿을 리턴하고, 아닐 때에는 타입에 맞추어 스크랩 목록을 리턴하도록 짜여져있다. 따라서, 스크랩 목록만 재조회하면, 해당 템플릿은 이미 스크랩이 존재하는 템플릿으로 분류되어 있는 상태이므로 스크랩이 없는 페이지에서 '선택 상태'를 만들려고 시도하는 것이다.

해결

상황적인 설명이 함께 하느라 말이 길어졌지만, 결론적으로는 코드 한 줄을 추가하여 해결했다. 👍

export const usePostCreateScrap = () => {
    const queryClient = useQueryClient();
    const isExistScrap = (error: any) => error.message === 'BR002';

    return useMutation(fetchPostCreateScrap, {
        onSuccess: () => {
          // 스크랩 개수 조회 invalidate 코드 삽입
            queryClient.invalidateQueries(['scrapCount']);
            queryClient.invalidateQueries(['scraps']);
            useDefaultSnackbar('스크랩이 생성되었습니다', 'success');
        },
        onError: (error) => {
            Sentry.captureException(error);
            isExistScrap(error) 
            ? useDefaultSnackbar('이미 존재하는 스크랩입니다.', 'error')
            : useDefaultSnackbar('스크랩 생성에 실패하였습니다.', 'error');
        },
        useErrorBoundary: false,
    });
}

새로운 사건

이제 이 타이밍 즈음에 후기를 적고 싶었으나 해당 문제를 해결한 이후 새로운 문제가 발생했다. 이 문제는 해결하면 2탄으로 돌아와야지...

profile
제일 재밌는 개발 블로그(희망 사항)

0개의 댓글