T
TanStack17mo ago
frail-apricot

New pattern for query factories

Hi @TkDodo 🔮, I was reading your latest article and I'm very curious about the new pattern you propose at the end of the article. I've been using react query for the past 3 years but I've never used query key factories, I'm 100% aligned with keeping the queryKey and queryFn as closed together as possible. most of my queries look like
useTickets = ({params, config}) => useQuery({
queryKey: ['tickets', params],
queryFn: () => fetchTickets (params),
...config
})
useTickets = ({params, config}) => useQuery({
queryKey: ['tickets', params],
queryFn: () => fetchTickets (params),
...config
})
I'm now starting a new project and I want to adopt a pattern to use consistently. And I'm curious about if I should keep doing like this and what's the best way to use typescript with this type of function signature could you please take a look at my attached screenshots and tell me if this is a correct implementation of a queryKey factory in your opinion? and can you tell me more if using custom hooks will still be encouraged or are you going to encourage using useQuery directly in the components?
No description
No description
4 Replies
flat-fuchsia
flat-fuchsia17mo ago
looks lovely ❤️ I encourage using useQuery directly in components because you'll never know what you'll need. Maybe you need to pass the options to queryClient.prefetchQuery. Or to useSuspenseQuery. or to useQueries. With a single object API, abstracting just the query options object away then passing the result directly to where you need is best also, the first query with ...config basically becomes:
const tickets = useQuery({
...ticketQuery.list(params)
select: (data) => data.length
})
const tickets = useQuery({
...ticketQuery.list(params)
select: (data) => data.length
})
so instead of abstracting away something where you need to pass in a full custom config, if you just useQuery directly, you can "inline" the options instead of:
useTickets({
select: (data) => data.length
})
useTickets({
select: (data) => data.length
})
yes it's a bit more to write but it's super flexible
frail-apricot
frail-apricotOP17mo ago
I feel so weird not writing custom hooks after all these years creating things like useTickets, however your point is completely valid, this makes it very flexible and saves you from creating things like useTicketsCount I've been thinking about this and I'm wondering if there is going to be something similar to queryOptions for mutations in the future. I always create custom hooks for mutations like useCreateTicket() but I rarely create arguments for these so if I need to create an optimistic update in the future I do it in the useCreateTicket function forces all users of that hook to run the optimistic update or whatever logic I applied. I don't know if that is good or bad as I can see both benefits and cons. What do you think?
frail-apricot
frail-apricotOP17mo ago
looks like I'm not the only one with that question, what do you think @TkDodo 🔮 are mutations moving in that direction too?
No description
flat-fuchsia
flat-fuchsia17mo ago
i haven't seen the need for mutationOptions. you can use satisfies to get enough type-safety

Did you find this page helpful?