В TanStack Query соглашения об именовании оказывают прямое влияние на:
Плохие naming conventions приводят к хаосу в query keys, дублированию запросов, ошибкам инвалидации и сложностям при рефакторинге.
Хорошие naming conventions формируют единый контракт между:
Основные зоны, где используются naming conventions:
Query key должен:
Наиболее распространённый формат:
['resource']
['resource', id]
['resource', filters]
['resource', id, subresource]
['users-list']
['getUsers']
['fetch-users']
['users_data']
Проблемы:
['users']
['userPosts']
['posts-list']
['profile_data']
Разные стили:
Это разрушает консистентность проекта.
['users']
['users', userId]
['users', userId, 'posts']
['posts']
['posts', postId]
Такой подход:
['users']
['users-active']
['users-admins']
['users-with-posts']
Проблемы:
['users']
['users', 'active']
['users', 'admins']
['users', 'with-posts']
Преимущества:
['users']
['users', userId]
['users', userId, 'posts']
['users', { role: 'admin' }]
На больших проектах ручное создание query keys становится источником ошибок.
Поэтому используется query key factory pattern.
export const userKeys = {
all: ['users'],
lists: () => [...userKeys.all, 'list'],
list: (filters) => [
...userKeys.lists(),
filters
],
details: () => [
...userKeys.all,
'detail'
],
detail: (id) => [
...userKeys.details(),
id
],
posts: (id) => [
...userKeys.detail(id),
'posts'
]
}
Все query keys находятся в одном месте.
Плохо:
['users']
['user']
['Users']
Хорошо:
userKeys.all
queryClient.invalidateQueries({
queryKey: userKeys.all
})
Изменение структуры происходит централизованно.
Стандартный подход:
useUsersQuery
useUserQuery
useCreateUserMutation
useUpdateUserMutation
useData
useFetch
useRequest
Непонятно:
useUsers
Проблема:
useUsersQuery
useUserQuery
useUserPostsQuery
useInfinitePostsQuery
useInfiniteCommentsQuery
useCreateUserMutation
useDeletePostMutation
useUpdateProfileMutation
Плохо:
const useUsersQuery = async () => {}
Hook не должен быть query function.
export const getUsers = async () => {}
export const getUser = async (id) => {}
export const createUser = async (payload) => {}
export const useUsersQuery = () => {}
export const useUserQuery = (id) => {}
getUsers
getUser
getPosts
createUser
createPost
updateUser
updateProfile
deleteUser
deleteComment
requestUsers
sendUser
handleUser
Непонятно:
Mutation naming должен отражать:
useCreateUserMutation
useUpdateUserMutation
useDeleteUserMutation
useUserMutation
useSaveMutation
useSubmitMutation
Проблемы:
optimisticallyUpdateUser
optimisticallyAddPost
rollbackUserUpdate
getUserFromCache
getPostsFromCache
setUserCache
setPostsCache
invalidateUsers
invalidatePosts
selectUserName
selectCompletedTodos
selectVisiblePosts
Infinite queries требуют явного отражения пагинации.
useInfinitePostsQuery
useInfiniteUsersQuery
usePostsQuery
Непонятно:
Рекомендуется:
['users', 'list']
['users', 'detail']
Не рекомендуется:
['usersList']
['usersDetail']
queryClient.invalidateQueries({
queryKey: ['users']
})
Иерархия становится визуально понятной.
['users', true, 10, 'active']
Невозможно понять значения.
['users', {
active: true,
limit: 10
}]
['posts', {
page: 1,
limit: 20
}]
['posts', {
cursor: 'abc123'
}]
При SSR особенно важна стабильность query keys.
Сервер:
['users']
Клиент:
['user']
Последствия:
На больших проектах используются namespace patterns.
['admin', 'users']
['admin', 'posts']
['public', 'posts']
['public', 'profile']
В microfrontend-проектах collision query keys особенно опасны.
['billing', 'users']
['crm', 'users']
['analytics', 'users']
['users', userId, 'permissions']
['permissions', userId]
Теряется контекст принадлежности.
features/
users/
api/
hooks/
queries/
mutations/
keys/
export const userKeys = {
all: ['users']
}
export const useUsersQuery = () => {}
TypeScript значительно усиливает эффективность naming conventions.
export const userKeys = {
all: ['users'] as const,
detail: (id: number) =>
['users', id] as const
}
IDE показывает структуру query keys.
Изменения распространяются автоматически.
queryKey: userKeys.detail(id)
queryClient.invalidateQueries({
queryKey: ['user-data']
})
queryClient.invalidateQueries({
queryKey: userKeys.all
})
useQuery({
queryKey: ['users'],
queryFn: fetchData
})
useQuery({
queryKey: userKeys.all,
queryFn: getUsers
})
TanStack Query DevTools напрямую зависят от качества query naming.
Хорошие naming conventions позволяют:
invalidateUsers
updateUserCache
syncPostsCache
useNotificationsPollingQuery
useRealtimeStatsQuery
pendingUserUpdates
offlinePostQueue
failedMutationsQueue
В enterprise-проектах naming conventions обычно стандартизируются документально.
use<Resource>Query
useInfinite<Resource>Query
use<Action><Resource>Mutation
get<Resource>
create<Resource>
update<Resource>
delete<Resource>
Нарушение naming conventions часто выявляется во время code review:
['usersData']
вместо:
['users']
или:
useDataQuery
вместо:
useUsersQuery
В TanStack Query naming conventions — это не косметический стиль.
Это часть:
Последовательные naming conventions превращают TanStack Query из набора hooks в полноценную предсказуемую систему управления серверным состоянием.