5

So the react-query cache is a key-value store but that is sort of limiting no? I thought that it was always best to keep network requests to a minimum since they take orders of magnitude longer than getting data from the cache. That being said, if I have a route /todos as the page for all the todos and a sub route /todos/FE234F32 as the page for some random todo, the query key for all the todos would be ["todos"] and the query key for the specific one would be ["todos", "FE234F32"], then say I visit the page with all the todos first, I would have the data for all the todos in the cache but then if I go to the page for the specific todo it would make a network request because there is no value for ["todos", "FE234F32"].

I understand I could do a getQueryData("todos") inside the query function for ["todos", "FE234F32"] so that I could check if the data is already in the cache but that sort of conditional based solution would make the code look terrible with a larger virtual hierarchy inside the cache. In general, it seems like most state solutions are hierarchical or object-based. but the key-value nature of react-query either causes fetching too much data and selecting down or fetching data that is already in the cache.

I could be completely off base here but I would love some insight/tips!

1 Answer 1

3

There are quite many ways to do this with react-query. If the data structure of your list query vs. your detail query are really the same, you can either pull it down the queries once you fetch the list, which will pre-populate the detail cache:

useQuery(
  'posts',
  fn,
  {
    onSuccess: data => data.map(post =>
      queryClient.setQueryData(['posts', id], post)
  }
)

Together with the right staleTime setting, you can avoid additional fetches.

You can also do the opposite and pull data once you mount the detail query via initialData:

useQuery(
  ['posts', id],
  fn,
  {
    initialData: () =>
      queryClient.getQueryData(['posts']?.find(post => post.id === id)
  }
)

finally, if your data is really always the same, you can think about using the select function to grab data from the list query instead of doing an extra fetch. This has the drawback of always refetching the whole list if you need data for one detail and you don't yet have data in the cache:

const usePosts = (select) => useQuery(['posts'], fetchPosts)
const usePost = (id) => usePosts(data => data.find(post => post.id === id))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.