React Query: заполняем кэш запросов
В React Query есть поддержка загрузки данных в Suspense, для этого нужно передать параметр suspense: true в настройки запроса. При использовании данного механизма нужно быть осторожным. Если у вас несколько запросов в одном компоненте, то возникает проблема “водопада” запросов. При рендере компонента React Query сообщает, что необходимо выполнить первый запрос, React ставит компонент на паузу и ждет выполнения. После успешного выполнения запроса, компонент перемонтируется заново и React Query сообщает, что необходимо выполнить второй запрос, и сценарий повторяется. Так возникает “водопад” запросов.
Чтобы избежать подобных проблем, Доминик Дорфмайстер в своем блоге поделился способами предварительного заполнения кэша для запросов.
Во-первых, предварительно загружайте данные до рендера компонента. Если проект поддерживает SSR, то загружайте данные на сервере. Если роутер поддерживает лоадеры, то загружайте в лоадерах.
const issuesQuery = { queryKey: ['issues'], queryFn: fetchIssues }
queryClient.prefetchQuery(issuesQuery)
function Issues() {
const issues = useQuery(issuesQuery)
}
Во-вторых, если у вас данные в списке и нужен отдельный элемент из списка, то его можно получить из кэша:
const data = useQuery({
queryKey: ['todos', 'detail', id],
queryFn: () => fetchTodo(id),
initialData: () => {
return queryClient
.getQueryData(['todos', 'list'])
?.find((todo) => todo.id === id)
},
})
Другой подход – создавать кэш для отдельного элемента после получения данных для списка:
const data = useQuery({
queryKey: ['todos', 'list'],
queryFn: async () => {
const todos = await fetchTodos()
todos.forEach((todo) => {
queryClient.setQueryData(['todos', 'detail', todo.id], todo)
})
return todos
},
})
Минус такого подхода в том, что данные могут устареть до момента, когда они понадобятся, либо эти данные могут вообще не понадобиться.
https://tkdodo.eu/blog/seeding-the-query-cache