Query Retries
'useQuery'가 데이터를 받아오는데 실패했을 때 (혹은 query functiondl error를 냈을때) TanStack Query는 자동적으로 query를 재시도한다. 재시도의 조건은 "설정한 retires의 숫자값(기본적으로는 3회인다.)에 도달하지 않았을 때" 혹은 "retires를 허락한 함수가 있는 상황
"이다.
이러한 retry설정은 개별query단위로도 가능하고, 전역적으로 모든 query에 대해서도 적용가능하다.
- retry = false -> retry가 없는 상황
- retry = 6 -> 재시도를 6번까지 제한
- retry = true -> 데이터가 받아져올때까지 재시도함(미친듯)
- retry = (failureCount, error) => ...를 설정하면 "왜 request가 실패했는지"에 기반한 커스텀 로직을 허락한다.
import { useQuery } from '@tanstack/react-query'
// Make a specific query retry a certain number of times
const result = useQuery({
queryKey: ['todos', 1],
queryFn: fetchTodoListPage,
retry: 10, // Will retry failed requests 10 times before displaying an error
})
Retry Delay
기본적으로는 TanStack Query의 retries는 요청실패에 즉각적으로 반응하지 않는다. 기본적으로 back-off-delay를 이용해 재시도 텀을 점진적으로 늘려간다. (예를들어 처음 재시도는 1초뒤, 그다음 시도는 2초뒤, 그다음 시도는 3초뒤..)
기본 retryDelay는 시도마다 2배로 증가하며, 1000ms에서 시작한다. 하지만 최대 30초는 넘기지 않는다.
// Configure for all queries
import {
QueryCache,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
},
},
})
function App() {
return <QueryClientProvider client={queryClient}>...</QueryClientProvider>
}
retryDelay를 개별적으로도, 전역적으로도 설정할 수 있지만 권장되지는 않는단다...왜?
정수로 설정하면 지연 시간이 항상 동일하게 적용된다.
const result = useQuery({
queryKey: ['todos'],
queryFn: fetchTodoList,
retryDelay: 1000, // Will always wait 1000ms to retry, regardless of how many retries
})
Paginated / Lagged Queries
페이지별로 데이터를 렌더링하는 paginated data는 매우 일반적인 UI 패턴이다. 또한 TanStack Query에서는 query key에 페이지에 관한 정보를 추가함으로써 작동한다.
const result = useQuery({
queryKey: ['projects', page],
queryFn: fetchProjects
})
이 예시를 실험해보면 이상한 점을 느끼게 될건데 그게 뭐냐면,
각 새 페이지가 새로운 쿼리처럼 취급되기때문에 UI는 성공상태와 로딩상태를 왔다갔다한다.
따라서 이러한 예시는 적절하지 않고, 후술할 keepPreviousData를 이용하면 된다.
keepPreviousData
keepPreviousData: true로 설정할 경우 바뀌는 것들
- The data from the last successful fetch is available while new data is being requested, even though the query key has changed.
- 새로운 데이터가 도착했을 때 이전의 데이터는 스무스하게 새로운데이터로 교체되어 보여진다.
- 'isPreviousData'는 쿼리가 현재 제공하는 데이터가 무엇인지 알 수 있게 해준다.
function Todos() {
const [page, setPage] = React.useState(0)
const fetchProjects = (page = 0) => fetch('/api/projects?page=' + page).then((res) => res.json())
const {
isLoading,
isError,
error,
data,
isFetching,
isPreviousData,
} = useQuery({
queryKey: ['projects', page],
queryFn: () => fetchProjects(page),
keepPreviousData : true
})
return (
<div>
{isLoading ? (
<div>Loading...</div>
) : isError ? (
<div>Error: {error.message}</div>
) : (
<div>
{data.projects.map(project => (
<p key={project.id}>{project.name}</p>
))}
</div>
)}
<span>Current Page: {page + 1}</span>
<button
onClick={() => setPage(old => Math.max(old - 1, 0))}
disabled={page === 0}
>
Previous Page
</button>{' '}
<button
onClick={() => {
if (!isPreviousData && data.hasMore) {
setPage(old => old + 1)
}
}}
// Disable the Next Page button until we know a next page is available
disabled={isPreviousData || !data?.hasMore}
>
Next Page
</button>
{isFetching ? <span> Loading...</span> : null}{' '}
</div>
)
}
Lagging Infinite Query results with 'keepPreviousData'
일반적이지는 않지만, keepPreviousData옵션은 'useInfiniteQuery'에서도 무리없이 사용할 수 있다.
결국 유저에게 캐시된 데이터를 보여주면서 시간이 흐름에 따라 Infinite query keys가 변경되는 작업이 동시에 이루어질 수 있다.
'React-Query' 카테고리의 다른 글
Guides&Concepts_(Initial Query Data) (0) | 2023.04.24 |
---|---|
Guides&Concepts_(Infinite Queries) (0) | 2023.04.23 |
Guides&Concepts_(React Query with Next.js) (0) | 2023.03.28 |
Guides&Concepts_(Paginated / Lagged Queries) (0) | 2023.03.27 |
Guides&Concepts_(Window Focus Refetching & Disabling/Pausing Queries) (0) | 2023.03.21 |