React Query: remove와 reset 살펴보기

제제 🍊·2023년 6월 30일
2

들어가며


OpenAI에서 ChatGPT를 사용하다보면 Regenerate response라는 버튼을 발견할 수 있다. 가장 마지막에 받아온 답변을 새롭게 받아오는 기능인데, 최근에 이와 같은 regeneration 기능을 구현할 일이 있었다.

UX 상 약간의 차이가 있다면 OpenAI에서 제공하는 regeneration 기능은 초기 답변도 다시 확인할 수 있을 뿐만 아니라 새로운 답변을 추가로 확인할 수 있는 반면, 초기 답변은 날리고 새로운 답변만 확인할 수 있다는 점이었다.

앱에는 서버 상태를 다루기 위해 React Query를 사용하고 있었고, React Query를 통해 regeneration 기능을 구현하기 위해 알아본 메소드와 그 과정을 정리해보고자 한다.

Regeneration 기능

Regeneration 기능을 React Query가 서버 상태를 다루는 개념으로 간단하게 풀어보자면, 캐싱된 쿼리 데이터의 제거 + 쿼리 데이터 새롭게 불러오기로 정리해볼 수 있다. 현재 화면에 렌더링 된 컴포넌트가 subscribe 중인 쿼리의 쿼리 데이터를 제거하고, 새로운 쿼리 데이터를 불러옴으로써 새로운 답변을 받아오는 과정을 그려낼 수 있다.

Regeneration = 캐싱된 쿼리 데이터 제거 + 쿼리 데이터 불러오기

기존에 앱 내에서 React Query의 refetch, invalidate 메소드를 자주 사용하고 있었는데, 쿼리 데이터를 새롭게 불러오는 역할만 수행하는 refetch, invalidate 메소드로는 regeneration 기능을 구현하기에는 한계가 존재했다. 새로운 쿼리 데이터를 받아오고 화면에 반영함으로써 "새로운 답변을 받아왔다"는 유저들에게 알릴 수 있지만, 기존 답변이 그대로 화면에 노출되고 있는 상태이므로 "새로운 답변을 받아오고 있는 중이다"를 유저들에게 알릴 수 없다.

retch, invalidate의 명세는 docs에서 확인해보자.
https://tanstack.com/query/v4/docs/react/reference/QueryClient

따라서 "새로운 답변을 받아오고 있는 중이다"를 유저들에게 알리기 위해 캐싱된 쿼리 데이터를 제거하는 역할을 수행할 메소드가 필요했고, React Query의 docs에서 후보군을 찾기 시작했다.

후보군 물색

캐싱된 쿼리 데이터를 제거하기 위해 발견한 메소드는 두가지가 존재했다.
바로 removereset 메소드이다.

React Query의 docs에서 명세를 가져오자면, 아래와 같다.

queryClient.removeQueries
The removeQueries method can be used to remove queries from the cache based on their query keys or any other functionally accessible property/state of the query.

queryClient.resetQueries
The resetQueries method can be used to reset queries in the cache to their initial state based on their query keys or any other functionally accessible property/state of the query.
This will notify subscribers — unlike clear, which removes all subscribers — and reset the query to its pre-loaded state — unlike invalidateQueries. If a query has initialData, the query's data will be reset to that. If a query is active, it will be refetched.

핵심은 remove는 쿼리 데이터를 제거한다는 것이고, reset은 쿼리 데이터를 초기 상태로 되돌린다는 것이다.

실제로 각각의 메소드가 어떻게 동작하는지 테스트를 진행해보았다.

테스트 환경


User Data를 쿼리 데이터로 갖는 쿼리를 subscribe 하고 있는 컴포넌트가 있다.
캐싱된 쿼리 데이터가 존재하면 User Data에 들어있는 값을 data 란에 노출(jeong)시키고, 캐싱된 쿼리 데이터가 없으면 data 란에 no data를 노출시킨다.
그리고 data 항목 아래에는 쿼리의 상태를 나타내는 isLoading, isFetching 값을 boolean 타입으로 노출하고 있다.

Remove 버튼을 클릭하면 유저 데이터를 담는 쿼리 키에 대해 queryClient.removeQueries({ queryKey: 유저 데이터를 담는 쿼리 키})를 호출하고,
Reset 버튼을 클릭하면 유저 데이터를 담는 쿼리 키에 대해 queryClient.resetQueries({ queryKey: 유저 데이터를 담는 쿼리 키})를 호출한다.

remove 테스트

remove 버튼을 클릭해보자.

화면에 아무런 변화가 없다.
하지만 React Query에서 제공하는 devTools를 보면, remove 메소드 호출 이전에 캐싱되어 있던 userData가 없어진 것을 볼 수 있다.

reset 메소드

reset 버튼을 클릭해보자.


화면에 노출되고 있던 jeong이라는 데이터가 no data로 바뀌고, isLoading과 isFetching 값이 모두 true로 바뀌면서 쿼리 데이터를 새롭게 받아온 이후 다시 data를 jeong으로 isLoading과 isFetching 값을 false로 나타내는 모습을 확인할 수 있다.

결과 분석

이러한 차이가 발생한 이유는 remove, reset 메소드 간의 차이에서 비롯된다.
remove는 캐싱된 쿼리 데이터를 제거할 뿐, 이를 subscribers에게 알리지 않는다.
반면, reset은 캐싱된 쿼리 데이터를 초기화할 뿐만 아니라(쿼리 자체를 pre-loaded 상태로 초기화함), subsribers에게 쿼리가 초기화되었음을 알린다.

이러한 차이를 통해 렌더링되어 있는 컴포넌트가 구독 중인 쿼리 데이터의 변화가 생기고, 리렌더링이 발생하면서 의도했던 regeneration이 구현되는 모습을 확인할 수 있다.

결론

화면에 보이는 쿼리 데이터를 지움과 동시에 새롭게 쿼리 데이터를 불러오고 싶다면 reset 메소드를 활용하자.

번외
결과를 곱씹어보면, remove 기능이 캐싱된 쿼리 데이터를 제거하는 역할을 했다면 새롭게 쿼리 데이터를 불러오는 과정은 다른 메소드가 담당해주어도 된다.
그리고 이런 역할은 앞서 소개한 refetch 메소드가 담당해줄 수 있다.
따라서 remove 메소드를 사용해야하는 상황이라면 refetch 메소드와 조합하여 regeneration 기능을 구현할 수 있을것이다.

profile
블로그 꿈나무 🌱

0개의 댓글