쿼리 취소
TanStack Query는 각 쿼리 함수에 AbortSignal 인스턴스를 제공합니다. 쿼리가 오래되거나 비활성 상태가 되면 이 signal은 중단됩니다. 즉, 모든 쿼리를 취소할 수 있으며 원하는 경우 쿼리 함수 내에서 취소에 대응할 수 있습니다. 가장 좋은 점은 자동 취소의 모든 이점을 누리면서도 일반적인 async/await 구문을 계속 사용할 수 있다는 것입니다.
기본 동작
기본적으로 Promise가 이행되기 전에 마운트 해제되거나 사용되지 않게 된 쿼리는 취소되지 않습니다. 즉, Promise가 이행된 후 결과 데이터는 캐시에서 사용할 수 있습니다. 이는 쿼리를 받기 시작했지만 완료되기 전에 컴포넌트가 마운트 해제된 경우에 유용합니다. 컴포넌트를 다시 마운트했을 때 쿼리가 아직 가비지 컬렉션되지 않았다면 데이터를 사용할 수 있습니다.
하지만 AbortSignal을 사용하면 Promise가 취소되고(예: 가져오기가 중단됨), 따라서 Query도 취소해야 합니다. 쿼리를 취소하면 해당 상태가 이전 상태로 되돌아갑니다.
HttpClient 사용하기
import { HttpClient } from '@angular/common/http'
import { injectQuery } from '@tanstack/angular-query-experimental'
postQuery = injectQuery(() => ({
enabled: this.postId() > 0,
queryKey: ['post', this.postId()],
queryFn: async (context): Promise<Post> => {
const abort$ = fromEvent(context.signal, 'abort')
return lastValueFrom(this.getPost$(this.postId()).pipe(takeUntil(abort$)))
},
}))
fetch 사용하기
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const todosResponse = await fetch('/todos', {
// Pass the signal to one fetch
signal,
})
const todos = await todosResponse.json()
const todoDetails = todos.map(async ({ details }) => {
const response = await fetch(details, {
// Or pass it to several
signal,
})
return response.json()
})
return Promise.all(todoDetails)
},
}))
axios 사용하기
import axios from 'axios'
const query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
}))
수동 취소
쿼리를 수동으로 취소하고 싶을 수 있습니다. 예를 들어 요청을 완료하는 데 시간이 오래 걸린다면 사용자가 취소 버튼을 클릭하여 요청을 중지하도록 할 수 있습니다. 이렇게 하려면 queryClient.cancelQueries({ queryKey })를 호출하기만 하면 되며, 그러면 쿼리가 취소되고 이전 상태로 되돌아갑니다. 쿼리 함수에 전달된 signal을 사용했다면 TanStack Query는 추가로 Promise도 취소합니다.
@Component({
template: `<button (click)="onCancel()">Cancel</button>`,
})
export class TodosComponent {
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: async ({ signal }) => {
const resp = await fetch('/todos', { signal })
return resp.json()
},
}))
queryClient = inject(QueryClient)
onCancel() {
this.queryClient.cancelQueries(['todos'])
}
}