Naming conventions

В TanStack Query соглашения об именовании оказывают прямое влияние на:

  • предсказуемость кеша;
  • читаемость query keys;
  • масштабируемость проекта;
  • удобство инвалидирования;
  • поддержку SSR и hydration;
  • работу DevTools;
  • переиспользование запросов;
  • сопровождение больших frontend-архитектур.

Плохие naming conventions приводят к хаосу в query keys, дублированию запросов, ошибкам инвалидации и сложностям при рефакторинге.

Хорошие naming conventions формируют единый контракт между:

  • API;
  • query-функциями;
  • hooks;
  • query keys;
  • mutations;
  • optimistic updates;
  • cache invalidation.

Структура именования в TanStack Query

Основные зоны, где используются naming conventions:

  1. Query keys
  2. Mutation keys
  3. Query hooks
  4. Mutation hooks
  5. Query functions
  6. API modules
  7. Cache utilities
  8. Selectors
  9. Infinite queries
  10. Optimistic update handlers

Naming conventions для query keys

Базовый принцип

Query key должен:

  • быть стабильным;
  • сериализуемым;
  • предсказуемым;
  • иерархическим;
  • масштабируемым.

Наиболее распространённый формат:

['resource']
['resource', id]
['resource', filters]
['resource', id, subresource]

Плохие query key naming patterns

Случайные строки

['users-list']
['getUsers']
['fetch-users']
['users_data']

Проблемы:

  • отсутствует единая структура;
  • невозможно предсказать key;
  • сложно делать invalidateQueries;
  • высокий риск дубликатов.

Смешивание стилей

['users']
['userPosts']
['posts-list']
['profile_data']

Разные стили:

  • camelCase;
  • kebab-case;
  • snake_case.

Это разрушает консистентность проекта.


Рекомендуемый стиль query keys

Использование resource-first подхода

['users']
['users', userId]
['users', userId, 'posts']
['posts']
['posts', postId]

Такой подход:

  • создаёт древовидную структуру;
  • упрощает invalidateQueries;
  • улучшает DevTools навигацию;
  • помогает масштабировать API.

Иерархия query keys

Плоская структура

['users']
['users-active']
['users-admins']
['users-with-posts']

Проблемы:

  • сложно фильтровать;
  • сложно инвалидировать;
  • высокий риск конфликтов.

Иерархическая структура

['users']
['users', 'active']
['users', 'admins']
['users', 'with-posts']

Преимущества:

  • частичная инвалидация;
  • логическая группировка;
  • предсказуемость.

Naming conventions для entity queries

Получение списка

['users']

Получение сущности

['users', userId]

Подресурс

['users', userId, 'posts']

Фильтрация

['users', { role: 'admin' }]

Query key factories

На больших проектах ручное создание query keys становится источником ошибок.

Поэтому используется query key factory pattern.


Пример query key factory

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'
  ]
}

Преимущества key factories

Централизация

Все query keys находятся в одном месте.


Защита от опечаток

Плохо:

['users']
['user']
['Users']

Хорошо:

userKeys.all

Удобный invalidateQueries

queryClient.invalidateQueries({
  queryKey: userKeys.all
})

Удобный refactoring

Изменение структуры происходит централизованно.


Naming conventions для hooks

use + Resource + Action

Стандартный подход:

useUsersQuery
useUserQuery
useCreateUserMutation
useUpdateUserMutation

Проблемные naming patterns

Неопределённые названия

useData
useFetch
useRequest

Непонятно:

  • что загружается;
  • какой endpoint используется;
  • query это или mutation.

Слишком общие названия

useUsers

Проблема:

  • query или mutation?
  • infinite query?
  • optimistic hook?
  • subscription?

Рекомендуемый naming style для hooks

Query hooks

useUsersQuery
useUserQuery
useUserPostsQuery

Infinite query hooks

useInfinitePostsQuery
useInfiniteCommentsQuery

Mutation hooks

useCreateUserMutation
useDeletePostMutation
useUpdateProfileMutation

Naming conventions для query functions

Отделение hooks от API

Плохо:

const useUsersQuery = async () => {}

Hook не должен быть query function.


Рекомендуемая структура

API layer

export const getUsers = async () => {}
export const getUser = async (id) => {}
export const createUser = async (payload) => {}

Hooks layer

export const useUsersQuery = () => {}
export const useUserQuery = (id) => {}

Naming conventions для API functions

REST-oriented naming

GET

getUsers
getUser
getPosts

CREATE

createUser
createPost

UPDATE

updateUser
updateProfile

DELETE

deleteUser
deleteComment

Антипаттерны API naming

Универсальные функции

requestUsers
sendUser
handleUser

Непонятно:

  • тип операции;
  • side effects;
  • HTTP semantics.

Naming conventions для mutations

Mutation naming должен отражать:

  • действие;
  • изменяемую сущность;
  • side effect.

Правильные mutation names

useCreateUserMutation
useUpdateUserMutation
useDeleteUserMutation

Неправильные mutation names

useUserMutation
useSaveMutation
useSubmitMutation

Проблемы:

  • отсутствует конкретика;
  • сложно искать в коде;
  • ухудшается DX.

Naming conventions для optimistic updates

Стандартный подход

optimisticallyUpdateUser
optimisticallyAddPost
rollbackUserUpdate

Naming conventions для cache helpers

Helpers для чтения кеша

getUserFromCache
getPostsFromCache

Helpers для записи кеша

setUserCache
setPostsCache

Helpers для invalidation

invalidateUsers
invalidatePosts

Naming conventions для selectors

Select-функции

selectUserName
selectCompletedTodos
selectVisiblePosts

Naming conventions для infinite queries

Infinite queries требуют явного отражения пагинации.


Хорошие примеры

useInfinitePostsQuery
useInfiniteUsersQuery

Плохие примеры

usePostsQuery

Непонятно:

  • обычный query;
  • infinite query;
  • cursor pagination;
  • offset pagination.

Naming conventions для query key segments

Строковые сегменты

Рекомендуется:

['users', 'list']
['users', 'detail']

Не рекомендуется:

['usersList']
['usersDetail']

Почему segmented naming лучше

Упрощение partial matching

queryClient.invalidateQueries({
  queryKey: ['users']
})

Упрощение DevTools

Иерархия становится визуально понятной.


Naming conventions для filter objects

Плохо

['users', true, 10, 'active']

Невозможно понять значения.


Хорошо

['users', {
  active: true,
  limit: 10
}]

Naming conventions для pagination

Offset pagination

['posts', {
  page: 1,
  limit: 20
}]

Cursor pagination

['posts', {
  cursor: 'abc123'
}]

Naming conventions для SSR

При SSR особенно важна стабильность query keys.


Ошибки SSR naming

Разные query keys

Сервер:

['users']

Клиент:

['user']

Последствия:

  • hydration mismatch;
  • повторный fetch;
  • потеря SSR state.

Naming conventions для multi-module architecture

На больших проектах используются namespace patterns.


Пример namespaced keys

['admin', 'users']
['admin', 'posts']

['public', 'posts']
['public', 'profile']

Naming conventions для microfrontend architecture

В microfrontend-проектах collision query keys особенно опасны.


Решение

['billing', 'users']
['crm', 'users']
['analytics', 'users']

Naming conventions для dependent queries

Хорошо

['users', userId, 'permissions']

Плохо

['permissions', userId]

Теряется контекст принадлежности.


Naming conventions для feature-based architecture

Структура

features/
  users/
    api/
    hooks/
    queries/
    mutations/
    keys/

Пример naming внутри feature

users/keys/userKeys.js

export const userKeys = {
  all: ['users']
}

users/hooks/useUsersQuery.js

export const useUsersQuery = () => {}

Naming conventions и TypeScript

TypeScript значительно усиливает эффективность naming conventions.


Typed query keys

export const userKeys = {
  all: ['users'] as const,

  detail: (id: number) =>
    ['users', id] as const
}

Преимущества typed naming

Автодополнение

IDE показывает структуру query keys.


Безопасный refactoring

Изменения распространяются автоматически.


Защита от несовместимых ключей

queryKey: userKeys.detail(id)

Naming conventions для invalidateQueries

Плохо

queryClient.invalidateQueries({
  queryKey: ['user-data']
})

Хорошо

queryClient.invalidateQueries({
  queryKey: userKeys.all
})

Naming conventions для query options

Плохо

useQuery({
  queryKey: ['users'],
  queryFn: fetchData
})

Хорошо

useQuery({
  queryKey: userKeys.all,
  queryFn: getUsers
})

Naming conventions и DevTools

TanStack Query DevTools напрямую зависят от качества query naming.

Хорошие naming conventions позволяют:

  • быстро искать queries;
  • понимать иерархию;
  • анализировать кеш;
  • отслеживать invalidation;
  • находить дубликаты.

Naming conventions для realtime systems

WebSocket updates

invalidateUsers
updateUserCache
syncPostsCache

Naming conventions для polling

useNotificationsPollingQuery
useRealtimeStatsQuery

Naming conventions для offline-first приложений

Queue naming

pendingUserUpdates
offlinePostQueue
failedMutationsQueue

Naming conventions для enterprise architecture

В enterprise-проектах naming conventions обычно стандартизируются документально.


Типовые правила enterprise naming

Query hooks

use<Resource>Query

Infinite hooks

useInfinite<Resource>Query

Mutation hooks

use<Action><Resource>Mutation

Query functions

get<Resource>
create<Resource>
update<Resource>
delete<Resource>

Naming conventions и code review

Нарушение naming conventions часто выявляется во время code review:

['usersData']

вместо:

['users']

или:

useDataQuery

вместо:

useUsersQuery

Naming conventions как часть архитектуры

В TanStack Query naming conventions — это не косметический стиль.

Это часть:

  • архитектуры кеша;
  • стратегии invalidation;
  • организации data layer;
  • масштабируемости frontend-приложения;
  • стабильности SSR;
  • поддержки optimistic updates;
  • поддержки realtime-механизмов;
  • производительности DevTools;
  • читаемости codebase.

Последовательные naming conventions превращают TanStack Query из набора hooks в полноценную предсказуемую систему управления серверным состоянием.