🔥 쿼리 취소
강의 목차
TanStack Query는 각 쿼리 함수에 AbortSignal 인스턴스를 제공합니다. 쿼리가 오래되거나 비활성화되면 이 신호가 중단됩니다. 이는 모든 쿼리를 취소할 수 있으며, 원한다면 쿼리 함수 내에서 취소에 대응할 수 있음을 의미합니다. 이 방식의 가장 큰 장점은 일반적인 async/await 문법을 그대로 사용하면서도 자동 취소의 모든 이점을 누릴 수 있다는 점입니다.
AbortController API는 대부분의 실행 환경에서 사용할 수 있습니다. 하지만 실행 환경이 이를 지원하지 않는다면 폴리필을 제공해야 합니다. 여러 가지 폴리필을 사용할 수 있습니다.
기본 동작
기본적으로 프로미스가 해결되기 전에 언마운트되거나 사용되지 않게 된 쿼리는 취소되지 않습니다. 이는 프로미스가 해결된 후에도 결과 데이터를 캐시에서 사용할 수 있음을 의미합니다. 쿼리 수신을 시작했지만 완료되기 전에 컴포넌트를 언마운트한 경우에 유용합니다. 컴포넌트를 다시 마운트하고 쿼리가 아직 가비지 컬렉션되지 않았다면 데이터를 사용할 수 있습니다.
그러나 AbortSignal을 사용하면 프로미스가 취소됩니다(예: fetch 중단). 따라서 쿼리도 취소해야 합니다. 쿼리를 취소하면 상태가 이전 상태로 되돌아갑니다.
fetch 사용하기
const query = useQuery({ queryKey: ['todos'], queryFn: async ({ signal }) => { const todosResponse = await fetch('/todos', { // 하나의 fetch에 신호 전달 signal, }) const todos = await todosResponse.json() const todoDetails = todos.map(async ({ details }) => { const response = await fetch(details, { // 또는 여러 개에 전달 signal, }) return response.json() }) return Promise.all(todoDetails) }, })
typescript
axios 사용하기 (v0.22.0 이상)
import axios from 'axios' const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => axios.get('/todos', { // `axios`에 신호 전달 signal, }), })
typescript
v0.22.0 미만의 axios 사용하기
import axios from 'axios' const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { // 이 요청에 대한 새로운 CancelToken 소스 생성 const CancelToken = axios.CancelToken const source = CancelToken.source() const promise = axios.get('/todos', { // 소스 토큰을 요청에 전달 cancelToken: source.token, }) // TanStack Query가 중단 신호를 보내면 요청 취소 signal?.addEventListener('abort', () => { source.cancel('TanStack Query에 의해 쿼리가 취소되었습니다') }) return promise }, })
typescript
XMLHttpRequest 사용하기
const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { return new Promise((resolve, reject) => { var oReq = new XMLHttpRequest() oReq.addEventListener('load', () => { resolve(JSON.parse(oReq.responseText)) }) signal?.addEventListener('abort', () => { oReq.abort() reject() }) oReq.open('GET', '/todos') oReq.send() }) }, })
typescript
graphql-request 사용하기
클라이언트 요청 메서드에서 AbortSignal을 설정할 수 있습니다.
const client = new GraphQLClient(endpoint) const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { client.request({ document: query, signal }) }, })
typescript
v4.0.0 미만의 graphql-request 사용하기
GraphQLClient 생성자에서 AbortSignal을 설정할 수 있습니다.
const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { const client = new GraphQLClient(endpoint, { signal, }) return client.request(query, variables) }, })
typescript
수동 취소
때로는 쿼리를 수동으로 취소하고 싶을 수 있습니다. 예를 들어, 요청이 완료되는 데 시간이 오래 걸리는 경우 사용자가 취소 버튼을 클릭하여 요청을 중지할 수 있게 할 수 있습니다. 이를 위해 queryClient.cancelQueries({ queryKey })
를 호출하면 됩니다. 이 호출은 쿼리를 취소하고 이전 상태로 되돌립니다. 쿼리 함수에 전달된 신호를 사용했다면 TanStack Query는 추가로 프로미스도 취소합니다.
const query = useQuery({ queryKey: ['todos'], queryFn: async ({ signal }) => { const resp = await fetch('/todos', { signal }) return resp.json() }, }) const queryClient = useQueryClient() return ( <button onClick={(e) => { e.preventDefault() queryClient.cancelQueries({ queryKey: ['todos'] }) }} > 취소 </button> )
typescript