codesquad-masters2024-team02 / issue-tracker

그룹 프로젝트
4 stars 3 forks source link

React Query - POST 요청 후 refetch 이슈 #62

Closed minjeongHEO closed 3 months ago

minjeongHEO commented 3 months ago

🐞 버그 설명

useMutation을 이용하여 POST요청 후 useQueryClient.invalidateQueries를 이용한 refetch 요청 불가



🚨버그가 발생한 상황

POST요청은 네트워크 탭에서 200코드를 확인하여 성공적으로 이루어지는 걸 확인, refetch하기 위해서 useQueryClient.invalidateQueries를 실행하려고 했지만 실패

... 작성중



😮 예상 동작 결과

POST요청이 성공(200)하였기 때문에 GET요청을 refetch하여 화면의 상태가 바뀔 것이라고 생각했습니다.



🤗 해결

  1. useMutation의 mutationFn 콜백 함수는 비동기 함수이므로 async await키워드를 붙여줬습니다.

    const { mutate: toggleIssueState } = useMutation({
    mutationFn: async ({ toIssueState, issueIds }) => {
      return await fetchIssueStateToggle(toIssueState, issueIds);
    },
    ...
  2. POST요청 후 respponse.json()을 호출하여 에러가 발생했습니다. 응답에 body가 없는 경우 response.json()을 호출하면 에러가 발생합니다. 응답에 JSON 데이터가 없을 경우에는 .json()을 호출하지 않고, 대신 상태 코드만 확인하거나 필요한 다른 정보를 반환할 수 있습니다.

    export const fetchIssueStateToggle = async (toIssueState, issueIds) => {
    try {
        const response = await fetch(`${import.meta.env.VITE_TEAM_SERVER}${ISSUE_DEFAULT_API_URI}${toIssueState ? 'close' : 'open'}`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ issueIds }),
        });
    
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    
        const result = await response.json(); // 이 부분에서 Error
    
        return result;
    } catch (error) {
        throw error;
    }
    };

    🔽

    export const fetchIssueStateToggle = async (toIssueState, issueIds) => {
    try {
    ...
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    
        return {
              status: response.status,
              statusText: response.statusText,
          };
    } catch (error) {
        throw error;
    }
    };
  3. 일단 2번에서 정상적으로 실행이 안됐기 때문에 useMutation의 onSuccess콜백이 호출되지 않았습니다. onSuccess 콜백이 호출되지 않는 문제는 useMutation의 mutationFn(2번 로직)이 제대로 Promise를 반환하지 않거나, 반환된 Promise가 올바르게 처리되지 않았기 때문이었습니다.

2번 오류를 처리하였지만 그래도queryClient.invalidateQueries 가 실행되지 않아, refetch가 여전히 되지 않았습니다.

  1. 쿼리 키의 일관성은 매우 중요합니다. 중요한 점은 타입까지 동일하게 해야 했습니다. ['issueDetail', '1']['issueDetail', 1]은 서로 다른 쿼리 키로 인식됩니다. refetch하려는 쿼리의 key는['issueDetail', '1'] 이었는데, invalidateQueries에서 실행 시키려던 쿼리의 키를 ['issueDetail', 1] 로 설정하였기 때문에 동일한 키라고 인식하지 못하여 refetch가 되지 않았던 것 입니다! string으로 타입을 일치시켜 해결하였습니다.

타입스크립트를 사용해야하는 이유를 확실히 느꼈습니다.....

queryClient.invalidateQueries({ queryKey: ['issueDetail', String(id)] })

invalidateQueries를 사용해서 키값에 해당하는 데이터를 invalidate(무효화) 시킨다. 그러면 해당 데이터가 즉각 stale 상태(데이터가 만료된 상태)가 되어 refetching 된다.

정리하자면: post 호출 → 성공시(onSuccess) ["키"] 값에 해당하는 데이터 날려버림 → 데이터 refetch