Capítulo 11 de 80
Query keys are arrays that must be JSON-serializable and unique to the data they identify; TanStack Query hashes them deterministically (object key order doesn't matter, array item order does), and every value a queryFn reads must be reflected in the key or the cache and refetch behavior silently break.
['todos']) up to string + serializable-object combinations (['todos', { status, page }]).['todos'], ['something', 'special'].['todo', 5], ['todo', 5, { preview: true }], ['todos', { type: 'done' }].{status, page} hashes the same as {page, status}); array item order does matter (['todos', status, page] ≠ ['todos', page, status]).queryFn closes over that can change must be part of the queryKey — otherwise the cache can't tell requests apart and won't refetch when that variable changes. This is exactly what the ESLint plugin's exhaustive-deps rule enforces.// Correct: todoId is a dependency, so it's in the key
function Todos({ todoId }) {
const result = useQuery({
queryKey: ['todos', todoId],
queryFn: () => fetchTodoById(todoId),
})
}
todoId closed over by queryFn also appears in queryKey — omitting it would make every todoId share one cache entry and never refetch on change.| Key example | Use case |
|---|---|
['todos'] | Generic list/index resource |
['todo', 5] | Single hierarchical resource by id |
['todo', 5, { preview: true }] | Same resource, parameterized variant |
['todos', { status, page }] | List filtered/paginated by params |
useEffect's deps.queryKey is passed into the QueryFunctionContext.exhaustive-deps enforces the dependency rule described here automatically.