Доки по разработке
This project is maintained by teniryte
queryKey определяет идентичность данных в кеше. Если ключи спроектированы плохо, дальше будут проблемы с инвалидацией, SSR, optimistic UI и Devtools.
['todos'], ['projects'].['todos', userId].['todos', { status, page }].['todos']
['todos', userId]
['todos', 'list', { status, page, sort }]
['todos', 'detail', todoId]
Удачная схема:
['todos', 'list', filters]['todos', 'detail', id]Она сразу даёт удобные маски для инвалидции.
export const todoKeys = {
all: ['todos'] as const,
lists: () => ['todos', 'list'] as const,
list: (filters: TodoFilters) => ['todos', 'list', filters] as const,
details: () => ['todos', 'detail'] as const,
detail: (id: string) => ['todos', 'detail', id] as const,
}
Плюсы:
queryOptions и infiniteQueryOptionsОфициально рекомендуемый паттерн:
import { queryOptions } from '@tanstack/react-query'
export function todoListOptions(filters: TodoFilters) {
return queryOptions({
queryKey: todoKeys.list(filters),
queryFn: () => fetchTodoList(filters),
staleTime: 30_000,
})
}
Такие опции можно переиспользовать везде:
useQuery(todoListOptions(filters))
queryClient.prefetchQuery(todoListOptions(filters))
queryClient.ensureQueryData(todoListOptions(filters))
Для бесконечных списков используйте infiniteQueryOptions.
await queryClient.invalidateQueries({ queryKey: ['todos'] })
Это затронет всё семейство:
['todos']['todos', 'list', ...]['todos', 'detail', ...]Если нужна ровно одна запись:
await queryClient.invalidateQueries({
queryKey: todoKeys.detail(id),
exact: true,
})
queryClient.getQueryData(todoKeys.detail(id))
queryClient.getQueryState(todoKeys.detail(id))
queryClient.setQueryData(todoKeys.detail(id), updater)
queryClient.removeQueries({ queryKey: todoKeys.lists() })
Полезные методы:
getQueryData читает данныеgetQueryState читает состояниеsetQueryData обновляет одну записьsetQueriesData обновляет группу записейremoveQueries удаляет записи из кешаqueryClient.setQueryData(todoKeys.detail(id), (old) =>
old
? {
...old,
title: newTitle,
}
: old,
)
Нельзя мутировать old на месте. Это приводит к трудноуловимым багам и ломает предсказуемость ререндеров.
В ключе храните:
Не храните в ключе:
Date.now()['todo', id] в одном месте и ['todos', id] в другом.['todos', { page, status }] и ['todos', { status, page }] без общего билдера.list/detail, из-за чего тяжело точечно инвалидировать записи.export const projectKeys = {
all: ['projects'] as const,
list: (filters: ProjectFilters) => ['projects', 'list', filters] as const,
detail: (id: string) => ['projects', 'detail', id] as const,
members: (id: string) => ['projects', 'detail', id, 'members'] as const,
}
Такой словарь даёт: