A library for creating typesafe standardized query keys, useful for cache management in @tanstack/query
MIT License
Bot releases are visible (Hide)
a7eb8d2
Thanks @lukemorales! - Fix contextQueries
not working with possibly undefined valuesPublished by github-actions[bot] 8 months ago
9b5401c
Thanks @lukemorales! - Improve mergeQueryKeys
type inference and improve type-safety for dynamic query keysPublished by github-actions[bot] over 1 year ago
1a9f74d
Thanks @lukemorales! - Fix type inference allowing extra keysPublished by github-actions[bot] over 1 year ago
e6b8389
Thanks @lukemorales! - Loosen types for TypedUseQueryOptions
and allow inference of dynamic query options generationPublished by github-actions[bot] over 1 year ago
1cf53a1
Thanks @lukemorales! - Refactor codebase and expose new TypedUseQueryOptions
typePublished by github-actions[bot] over 1 year ago
142024d
Thanks @s-bondarenko! - Implemented create-mutation-keys
function for creating of mutation keys142024d
Thanks @s-bondarenko! - Added possibility to merge mutation keys with query keysPublished by github-actions[bot] almost 2 years ago
#47 7013e19
Thanks @lukemorales! - Add support for longer query keys in the QueryOptions
pattern
#34 abb3596
Thanks @wconnorwalsh! - Replace internal types with official @tanstack/query-core
types
0518ac4
Thanks @lukemorales! - Fix conflicting typesPublished by github-actions[bot] almost 2 years ago
f74ec8e
Thanks @lukemorales! - Fix published typesd8bdb58
Thanks @lukemorales! - Fix wrong published types for contextual queries#20 ba47907
Thanks @lukemorales! - ## Generate query options and add support for nested keys
New in @lukemorales/query-key-factory
is support for nested keys and generation of query options, adopting the query options overload as first class citizen, in preparation for React Query v5 roadmap.
const people = createQueryKeys('people', {
person: (id: number) => ({
queryKey: [id],
queryFn: () => api.getPerson({ params: { id } }),
contextQueries: {
ships: {
queryKey: null,
queryFn: () =>
api.getShipsByPerson({
params: { personId: id },
}),
},
film: (filmId: string) => ({
queryKey: [filmId],
queryFn: () =>
api.getFilm({
params: { id: filmId },
}),
}),
},
}),
});
Each entry outputs an object that can be used in the query options overload in React Query:
console.log(people.person('person_01'));
// => output:
// {
// queryKey: ['people', 'person', 'person_01'],
// queryFn: () => api.getPerson({ params: { id: 'person_01' } }),
// _ctx: { ...queries declared inside "contextQueries" }
// }
Then you can easily just use the object in useQuery
or spread it and add more query options to that observer:
export const Person = ({ id }) => {
const personQuery = useQuery(people.person(id));
return {
/* render person data */
};
};
export const Ships = ({ personId }) => {
const shipsQuery = useQuery({
...people.person(personId)._ctx.ships,
enabled: !!personId,
});
return {
/* render ships data */
};
};
export const Film = ({ id, personId }) => {
const filmQuery = useQuery(people.person(personId)._ctx.film(id));
return {
/* render film data */
};
};
All query key values should now be an array. Only the first level keys (those not dynamically generated) can still be declared as null
, but if you want to pass a value, you will need to make it an array.
export const todosKeys = createQueryKeys('todos', {
mine: null,
- all: 'all-todos',
+ all: ['all-todos'],
- list: (filters: TodoFilters) => ({ filters }),
+ list: (filters: TodoFilters) => [{ filters }],
- todo: (todoId: string) => todoId,
+ todo: (todoId: string) => [todoId],
});
You can still use objects to compose a query key, but now they must be inside an array because plain objects are now used for the declaration of the query options:
export const todosKeys = createQueryKeys('todos', {
- list: (filters: TodoFilters) => ({ filters }),
+ list: (filters: TodoFilters) => ({
+ queryKey: [{ filters }],
+ }),
});
With the new API, the output of an entry will always be an object according to what options you've declared in the factory (e.g.: if you returned an array or declared an object with only queryKey
, your output will be { queryKey: [...values] }
, if you also declared queryFn
it will be added to that object, and contextQueries
will be available inside _ctx
):
export const todosKeys = createQueryKeys('todos', {
todo: (todoId: string) => [todoId],
list: (filters: TodoFilters) => {
queryKey: [{ filters }],
queryFn: () => fetchTodosList(filters),
},
});
- useQuery(todosKeys.todo(todoId), fetchTodo);
+ useQuery(todosKeys.todo(todoId).queryKey, fetchTodo);
- useQuery(todosKeys.list(filters), fetchTodosList);
+ useQuery(todosKeys.list(filters).queryKey, todosKeys.list(filters).queryFn);
// even better refactor, preparing for React Query v5
+ useQuery({
+ ...todosKeys.todo(todoId),
+ queryFn: fetchTodo,
+ });
+ useQuery(todosKeys.list(filters));
The helper types to infer query keys in the created store reflect the new output, to account for all possible use cases:
type TodosKeys = inferQueryKeys<typeof todosKeys>;
- type SingleTodoQueryKey = TodosKeys['todo'];
+ type SingleTodoQueryKey = TodosKeys['todo']['queryKey'];
#20 ba47907
Thanks @lukemorales! - ## Remove deprecated methods
Since v0.6.0
, the default
key and and toScope
method have been deprecated from the package.
default
and toScope
removed from implementationdefault
key and toScope
method have been officially removed from the code, which means that if you try to access them, you will either receive undefined
or your code will throw for trying to invoke a function on toScope
that does not exist anymore.
_def
key and deprecate default
and toScope
createQueryKeyStore
to allow declaring all feature keys in one placemergeQueryKeys
to create single access point to all query keysinferQueryKeys
type to create interface from result of createQueryKeys
Published by lukemorales almost 2 years ago
Fix wrong published types
Published by lukemorales almost 2 years ago
Force re-release
Published by lukemorales almost 2 years ago
#20 ba47907
Thanks @lukemorales! - ## Generate query options and add support for nested keys
New in @lukemorales/query-key-factory
is support for nested keys and generation of query options, adopting the query options overload as first class citizen, in preparation for React Query v5 roadmap.
const people = createQueryKeys('people', {
person: (id: number) => ({
queryKey: [id],
queryFn: () => api.getPerson({ params: { id } }),
contextQueries: {
ships: {
queryKey: null,
queryFn: () =>
api.getShipsByPerson({
params: { personId: id },
}),
},
film: (filmId: string) => ({
queryKey: [filmId],
queryFn: () =>
api.getFilm({
params: { id: filmId },
}),
}),
},
}),
});
Each entry outputs an object that can be used in the query options overload in React Query:
console.log(people.person('person_01'));
// => output:
// {
// queryKey: ['people', 'person', 'person_01'],
// queryFn: () => api.getPerson({ params: { id: 'person_01' } }),
// _ctx: { ...queries declared inside "contextQueries" }
// }
Then you can easily just use the object in useQuery
or spread it and add more query options to that observer:
export const Person = ({ id }) => {
const personQuery = useQuery(people.person(id));
return {
/* render person data */
};
};
export const Ships = ({ personId }) => {
const shipsQuery = useQuery({
...people.person(personId)._ctx.ships,
enabled: !!personId,
});
return {
/* render ships data */
};
};
export const Film = ({ id, personId }) => {
const filmQuery = useQuery(people.person(personId)._ctx.film(id));
return {
/* render film data */
};
};
All query key values should now be an array. Only the first level keys (those not dynamically generated) can still be declared as null
, but if you want to pass a value, you will need to make it an array.
export const todosKeys = createQueryKeys('todos', {
mine: null,
- all: 'all-todos',
+ all: ['all-todos'],
- list: (filters: TodoFilters) => ({ filters }),
+ list: (filters: TodoFilters) => [{ filters }],
- todo: (todoId: string) => todoId,
+ todo: (todoId: string) => [todoId],
});
You can still use objects to compose a query key, but now they must be inside an array because plain objects are now used for the declaration of the query options:
export const todosKeys = createQueryKeys('todos', {
- list: (filters: TodoFilters) => ({ filters }),
+ list: (filters: TodoFilters) => ({
+ queryKey: [{ filters }],
+ }),
});
With the new API, the output of an entry will always be an object according to what options you've declared in the factory (e.g.: if you returned an array or declared an object with only queryKey
, your output will be { queryKey: [...values] }
, if you also declared queryFn
it will be added to that object, and contextQueries
will be available inside _ctx
):
export const todosKeys = createQueryKeys('todos', {
todo: (todoId: string) => [todoId],
list: (filters: TodoFilters) => {
queryKey: [{ filters }],
queryFn: () => fetchTodosList(filters),
},
});
- useQuery(todosKeys.todo(todoId), fetchTodo);
+ useQuery(todosKeys.todo(todoId).queryKey, fetchTodo);
- useQuery(todosKeys.list(filters), fetchTodosList);
+ useQuery(todosKeys.list(filters).queryKey, todosKeys.list(filters).queryFn);
// even better refactor, preparing for React Query v5
+ useQuery({
+ ...todosKeys.todo(todoId),
+ queryFn: fetchTodo,
+ });
+ useQuery(todosKeys.list(filters));
The helper types to infer query keys in the created store reflect the new output, to account for all possible use cases:
type TodosKeys = inferQueryKeys<typeof todosKeys>;
- type SingleTodoQueryKey = TodosKeys['todo'];
+ type SingleTodoQueryKey = TodosKeys['todo']['queryKey'];
#20 ba47907
Thanks @lukemorales! - ## Remove deprecated methods
Since v0.6.0
, the default
key and and toScope
method have been deprecated from the package.
default
and toScope
removed from implementationdefault
key and toScope
method have been officially removed from the code, which means that if you try to access them, you will either receive undefined
or your code will throw for trying to invoke a function on toScope
that does not exist anymore.
queryKey
by @lukemorales in https://github.com/lukemorales/query-key-factory/pull/23
infer
type helpers to work with new API by @lukemorales in https://github.com/lukemorales/query-key-factory/pull/24
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.6.0...v1.0.0
Published by lukemorales about 2 years ago
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.6.0...v0.6.1
Published by lukemorales about 2 years ago
_def
and deprecate default
and toScope
by @lukemorales in https://github.com/lukemorales/query-key-factory/pull/14
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.5.0...v0.6.0
Published by lukemorales about 2 years ago
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.4.0...v0.5.0
Published by lukemorales about 2 years ago
mergeQueryKeys
util by @lukemorales in https://github.com/lukemorales/query-key-factory/pull/11
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.3.2...v0.4.0
Published by lukemorales about 2 years ago
inferQueryKeys
type by @joaom00 in https://github.com/lukemorales/query-key-factory/pull/9
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.3.1...v0.3.2
Published by lukemorales about 2 years ago
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.3.0...v0.3.1
Published by lukemorales about 2 years ago
Full Changelog: https://github.com/lukemorales/query-key-factory/compare/v0.2.1...v0.3.0
Published by lukemorales about 2 years ago
Published by lukemorales about 2 years ago