본문 바로가기

개발/개발일지

[Trouble Shooting] useMutation을 활용한 생성, 수정, 삭제

서버 데이터를 관리하기 위한 React Query의 사용

React-Query는 데이터를 fetching 해온 후, 데이터를 캐싱하게 되고, stale 상태의 데이터를 refetching 하게 된다.

브라우저에서 사용자들은 화면을 바라보고 있을 때, 페이지가 전환될 때, (클릭과 같이) 데이터를 요청할 때 최신의 데이터를 받아봐야한다.

React-Query의 경우 WindowFocus, Mount, Reconnect, stale data 의 상황에서 refetch를 실행함으로써, 데이터의 fresh 한 상태를 유지한다.

 

 

유저정보를 전역상태관리함.

=> 유저정보에 전역상태관리툴을 사용한 이유는, React-Query는 서버 데이터 관리에 특화되어 있기 때문이다.

(서버를 거치느냐, 브라우저에만 국한되는 사용자 혼자서만 사용할 데이터냐)

서버에 접속하기 위한 클라이언트의 상태 값은 Redux를 이용해서 전역 상태관리하고,

서버사이드의 상태 값을 전달받아 화면에 보여주거나 상태 값을 변경하는 요청을 전달하는 부분들을 React-Query를 사용하여 역할에 따라 사용하는 것을 달리함. refetching 옵션들을 통해 서버의 데이터를 동기화할 수 있고, useMutation을 사용할 때도, defaultOptions에 onError를 추가하여, POST, PUT, DELETE 등의 API 실패 시, 안내 문구를 띄우는 기능도 유용하게 사용하기 위함.

 


 

useMutation 오류 발생(queryClient.invalidateQueries가 작동하지 않는 문제)

서버 데이터를 관리하는 과정에서 데이터가 실시간으로 반영된다면, 자신이 작성한 글, 좋아요버튼 클릭상태, 마이페이지 카테고리별 글 모아보기 등이 실시간으로 작동 되면서 유저들이 편하게 서비스를 이용할 수 있다. 서버 데이터 변경작업을 요청하기 위해 useMutation를 사용한다.

 

mutation.mutate의 onSuccess callback 안에서 console.log와 navigation 작업은 정상적으로 작동했으나, invalidate query가 제대로 동작하지 않는 문제가 생겼다. 

 

동일한 쿼리키를 사용하지 않는 것이 뮤테이션 오류를 발생시키지 않을까라는 의문을 가졌다.

쿼리키를 사용하는 방식에 있어서 전체게시물 목록을 불러오는 query문에는 ['posts', areaSelected] 를 사용하고, invalidate를 할때는 ['posts'] 를 사용해서 쿼리를 stale 시켰기에 이걸 다른 키로 인식하는 것 같다는 생각이 들어 동일한 [queryKeys.posts] 쿼리키를 사용했다.

 

이동하면서 컴포넌트가 unmount 되는 상황이 발생하고 이로 인해 뮤테이션 오류가 생기는 것이 아닐까라는 생각을 했다.

 

mutation 중 하나의 컴포넌트에서 다른 컴포넌트로 이동하는 상황에서

mutation.mutate의 후속 작업(callback)은 작업이 이루어지는 해당 컴포넌트가 unmount되면 (우리의 경우, 작성페이지가 닫기는 경우) 정상 작동하지 않는다고 한다. 
그래서 컴포넌트 이동을 하는 navigation을 callback에 배치하였고(기존에는 submit button 클릭하면 바로 이동하게 구현), return문도 넣어서 invalidate 작업도 기다리게 해주었다.

 const { mutate: onAdd } = useMutation(onSubmitPost, {
    onSuccess: () => {
      navigate('/posts');
      return queryClient.invalidateQueries([queryKeys.posts]);
    },
    onError: (err) => {
      console.log(err.respose);
      alert('게시글 등록에 실패하였습니다');
    }
  });

 

=>게시글이 제대로 등록되고 invalidate 되어 추가된 쿼리 data가 들어오지만, 유저가 볼수 있는 화면에는 새로 추가된 게시물이 바로 나타나지 않는 현상이 일어났다. (테스트를 해본 조원 중 일부는 제대로 작동하고, 일부는 제대로 작동을 하지 않는 문제가 발생해서 제대로 고쳐진게 아니라고 생각했다) 새로 고침을 했을때는 제대로 나타났는데, dev tool을 활용해 stale을 하고 fresh한 데이터를 받아오는데도 제대로 fetch가 일어나지 않는 현상을 발견해서 window.location.href를 사용해 새로 데이터를 패칭할 수 있게 구현하여 해결했다. 근데 이 방법이 근본적으로 mutate 오류를 해결한 것이 아닌 것 같아 새로운 방법을 고민했다. 

 

 

=>onSuccess callback을 비동기 처리해서 해결!

 

await는 말 그대로 프라미스가 처리될 때까지 함수 실행을 기다리게 만든다. 프라미스가 처리되면 그 결과와 함께 실행이 재개된다. (return을 해서 기다려주는거랑 어떤 차이가 있을까?) 이런 await의 효과를 이용해서 onSuccess callback 이 실행될때 쿼리를 invalidate를 시키는 함수 실행의 결과를 기다리게 하고 이후 네비게이션을 시키는 방식으로 비동기적인 callback을 동기처럼 작동하게 함으로써, 문제를 해결했다. (게시글 생성, 수정, 삭제는 해결)

const { mutate: onAdd } = useMutation(onSubmitPost, {
    onSuccess: async() => {
      await queryClient.invalidateQueries([queryKeys.posts]);
      return navigate('/posts');
    },
    onError: (err) => {
      console.log(err.respose);
      alert('게시글 등록에 실패하였습니다');
    }
  });
 
다시 돌아가서 동일한 쿼리키를 사용하지 않는 것이 뮤테이션 오류를 발생시키지 않을까라는 가설을 다시 검증했다.
 

await queryClient.invalidateQueries([queryKeys.myPostsList], { refetchType: 'all' });