I am learning TanStack Query (previously React Query) and so far I menaged to successfully fetch data. I am wondering how to mutate it so that I can take the advantage of all TanStack Query features – especially caching. Here is my code so far:
import { useQuery } from "@tanstack/react-query"
type Task {
id: number,
name: string
}
function convertDataToTasks(data:any[]){
const tasks:Task[] = [];
data.forEach( item => {
tasks.push({ id: item.id, name: item.title})
});
return tasks;
}
export function toDosQuery() {
return useQuery({
queryKey: ['todos'],
queryFn: async (): Promise<Array<any>> => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos')
return await response.json()
},
})
}
export function TaskLabel({task}:{task:Task}) {
return (
<article>
{ task.name }
</article>
)
}
export function SidebarTasksList() {
const { status, data, error, isFetching } = toDosQuery()
return (
<section>
{status === 'pending' ? (
'Loading...'
) : status === 'error' ? (
<span>Error: {error.message}</span>
) : (
convertDataToTasks(data).map( task => (
<TaskLabel task={task} key={task.id}/>
))
)}
<span>{isFetching ? "Fetching new data" : ""}</span>
</section>
)
}
function App() {
return (
<>
app root cmp
<SidebarTasksList />
</>
)
}
export default App
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import App from './App.tsx'
import './index.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<QueryClientProvider client={new QueryClient}>
<ReactQueryDevtools />
<App />
</QueryClientProvider>
</StrictMode>
)
Right now I parse received data by passing it into dedicated function convertDataToTasks()
in JSX returned from component which feels unelegant. I would like to keep already parsed data in the Query cache as I plan on consuming external public API which provide much more details and different formating than what I will need for this app.
2
Answers
If I’m understanding your post/question correctly you are saying you would prefer to not call
convertDataToTasks
inline in JSX when rendering and would like React-Query to cache the data you want to render from. If this is the case then I believe the solution is as simple as moving theconvertDataToTasks
call into thequeryFn
query handler you are using.Example:
Previously cached data: the returned JSON placeholder data
Currently cached data: the mapped
Task
dataDemo
Start by setting up a custom hook with
useMutation
:Now to actually do something when you update the data, we must add the
onSuccess
option. We can use both invalidateQueries and setQueryData for handling cache updates.The onSuccess callback in the example below identifies the todo item with the same ID as the updated data and modifies it directly without refetching the entire todo list.
Updating a single todo item after mutation:
It’s up to you whether you want to update individual items or refetch the entire list. Here’s a comment from TkDodo that might help you decide:
Invalidate and refetch the entire list after mutation:
Now it’s up to you how you want to use the functions described above. Here’s a quick example to show how you can put it all together: