쿼리 취소에 관하여:
직접 useFetch와 같은 훅을 구현할 경우, unmount된 경우에도 상태 설정 훅을 호출하여 개발 환경에서 오류 메세지를 마주치는 경우가 많죠.
즉, 보통은 요청을 일단 보내면 이후에 필요 없어져도 요청은 그대로 두고 응답받은 내용을 사용 안 하는 식으로만 구현합니다.
React-Query와 같은 라이브러리를 사용하여도 해당 전략은 마찬가지입니다.
...기본적으로 프로미스가 리졸브되기 전에 마운트 해제되거나 사용되지 않는 쿼리는 취소되지 않습니다.
즉, 프로미스가 리졸브된 후 결과 데이터를 캐시에서 사용할 수 있음을 의미합니다.
이 동작은 쿼리 수신을 시작했지만 완료되기 전에 컴포넌트를 마운트 해제한 경우 유용합니다.
컴포넌트를 다시 마운트하였을 때, 쿼리가 아직 가비지 수집되지 않은 경우 해당 데이터를 사용할 수 있습니다.
간단한 HTTP 요청은 응답이 꽤 빠르기 때문에 괜찮을 수도 있지만,
무거운 요청(프로미스)의 경우는 불필요한 네트워크 트래픽을 낭비하게 되거나, 커넥션을 차지하고 있으므로 취소하는 것이 좋습니다.
React Query를 사용하면 아주 쉽게 요청(프로미스) 취소를 위임할 수 있는 것, 알고 계셨나요?
자동으로 쿼리 취소하기
공식문서에는 다음과 같이 적혀 있습니다.
React Query는 런타임 환경에서 사용 가능한 경우, AbortSignal instance와 함께 각 쿼리 함수를 제공합니다.
(폴리필 가능)
쿼리 실행 도중 쿼리가 비활성화(컴포넌트에서 사용하지 않음) 되었거나, 새로운 결과가 필요하면 해당 쿼리를 중단합니다.
이는 다음과 같은 행위를 의미합니다.
- 컴포넌트가 마운트 해제될 때, React Query가 진행 중인 쿼리 실행 / 요청을 취소할 수 있도록 합니다.
- 혹은 사용자가 버튼을 클릭하여 요청을 취소할 수 있도록 합니다.
주 : Promise의 cancel 메서드는 Bluebird 사용 시
참고 : https://benlesh.medium.com/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082
예시 : fetch 사용
const query = useQuery({
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 버전 0.22.0+ 이상 사용 시
import axios from 'axios'
const query = useQuery({
queryKey: ['todos'],
queryFn: ({ signal }) =>
axios.get('/todos', {
// Pass the signal to `axios`
signal,
}),
})
위와 같이 사용하기 정말 쉽습니다.
이 외에도 여러 API에 대한 예제가 있으니 공식 문서를 확인하시기 바랍니다.
수동으로 쿼리 취소하기
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'] })
}}>Cancel</button>
)
주 : 리액트 쿼리의 쿼리를 중단하는 것과, promise 취소는 다른 것이니 주의할것!
promise가 resolve된 이후 로직의 실행을 중단하는것임
참고
https://blog.outsider.ne.kr/1602
https://benlesh.medium.com/promise-cancellation-is-dead-long-live-promise-cancellation-c6601f1f5082
https://medium.com/@icjoseph/using-react-to-understand-abort-controllers-eb10654485df
'FrontEnd' 카테고리의 다른 글
API 디자인 : API 디자인의 기본과 API 디자인 테이블 (1) | 2022.11.13 |
---|---|
CSS Position Sticky 문제 해결하기 (0) | 2022.11.03 |
[Remix] 풀 스택 컴포넌트(Full Stack Components) (0) | 2022.11.03 |
Critical Rendering Path 최적화하기 (0) | 2022.10.31 |
리액트와 유닛 테스트를 위한 클린 아키텍처 [부제, 의존성 주입은 정말 필요한가?] (0) | 2022.10.30 |