ReactQuery에서 InvalidateQuery 와 SetQueryData 로 데이터를 업데이트 하기

Universe·2023년 2월 2일
6

서론

진행하는 프로젝트에 그림일기에 북마크를 설정할 수 있는 기능이 있다.
처음에는 단순하게 mutation 을 사용해 해당 값을 바꾸고
invalidateQuery 로 기존의 데이터를 무효화 한 뒤 refetch 하는 식으로 구현했는데,
일기의 갯수가 많아지자 문제가 발생했다.

일기를 refetch 하는데 걸리는 시간때문에 북마크의 전환이 느려지는 것이다.
저 시간을 기다리다가는 늙어 죽을 것 같았으므로 대책이 필요했다.






본론

invalidateQuery

const { mutate: bookmarkMutate } = useMutation({
    mutationFn: () => postsApi.bookmark(postId),
    onSuccess: () => {
      queryClient.invalidateQueries(["Allposts"]);
    },
  });

북마크 버튼을 눌러 mutate 를 실행하여 성공하면
invalidateQueryies 로 post를 업데이트 하는 로직

invalidateQuery 는 캐싱된 쿼리를 무효화 하는데 사용된다.
쿼리 데이터가 변경되었으니 새 데이터를 반영하도록 기존의 쿼리를 버리고
새로운 버전의 데이터를 반영한다.

요청에 의한 피드백으로 서버와 클라이언트가 같은 버전의 데이터를 가질 수 있다는 장점이 있지만
데이터가 많아지면 그만큼의 데이터를 버리고 다시 불러오는 과정을 거치게 되므로
사용자 입장에서는 답답할 수 밖에 없다.

setQueryData

const { mutate: bookmarkMutate } = useMutation({
    mutationFn: () => postsApi.bookmark(postId),
    onSuccess: () => {
      const allPosts = queryClient.getQueryData(["Allposts"]);
      const post = allPosts.filter((e) => e.postId === postId)[0];

      queryClient.setQueryData(
        ["Allposts"],
        allPosts.map((e) =>
          e === post ? { ...post, bookmark: !post.bookmark } : e
        )
      );
    },
  });

setQueryData는 쿼리 데이터를 수동으로 설정한다.
서버에서 데이터를 다시 가져올 필요 없이 쿼리 데이터를 내부 로직 자체에서 업데이트한다.
다음 네트워크 요청을 기다릴 필요가 없으므로 사용자 입장에서는 즉각적인 피드백을 받을 수 있다.
정확한 의미에서는 서버와 실시간으로 동기화 되고 있다고 볼 수는 없지만
보이는 화면에서는 마치 피드백이 즉각적으로 이루어지고 있는 것 처럼 보여지기 깨문에
사용자 경험 측면에서 유리하다.

수정 이후

기다리다가 늙어 죽을 정도는 아니게 되었다 ! 🥳






결론

이 두 가지 방법을 적절하게 사용하여 데이터를 효과적으로 관리하는 것이 바람직하다.
항상 닭 잡는 데에는 닭 잡는 칼을, 소 잡는 데에는 소 잡는 칼을 사용하는 것이 좋겠다.
🤔

여담이지만 조금 더 효율화 된 로직을 짤 수 없었을까 ?
서버에서 refetch를 하지 않아서 동작이 빨라지긴 했지만
결국 100개가 넘어가는 일기를 하나하나 map 메소드로 대조해야 하는데
100개가 아니라 1000개 이상의 일기가 있었다면
똑같이 딜레이 현상을 겪게 될 것 같다는 생각이 들었다.

profile
Always, we are friend 🧡

1개의 댓글

comment-user-thumbnail
2023년 10월 23일

map메소드를 사용하는 방법도있지만 공간복잡도를 활용한 Map객체로 비교하는것도 성능향상에 도움이됩니다 !

답글 달기