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.
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 the convertDataToTasks
call into the queryFn
query handler you are using.
Example:
interface JsonPlaceholderTask {
userId: number;
id: number;
title: string;
completed: boolean;
}
type Task = {
id: number;
name: string;
};
const convertDataToTasks = (data: JsonPlaceholderTask[]) =>
data.map((item) => ({ id: item.id, name: item.title })) as Task[];
function toDosQuery() {
return useQuery({
queryKey: ["todos"],
queryFn: async (): Promise<Task[]> => {
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos"
);
const data: JsonPlaceholderTask[] = await response.json();
return convertDataToTasks(data);
},
});
}
function SidebarTasksList() {
const { status, data, error, isFetching } = toDosQuery();
return (
<section>
{status === "pending" ? (
"Loading..."
) : status === "error" ? (
<span>Error: {error.message}</span>
) : (
data.map((task) => <TaskLabel task={task} key={task.id} />)
)}
<span>{isFetching ? "Fetching new data" : ""}</span>
</section>
);
}
Previously cached data: the returned JSON placeholder data
Currently cached data: the mapped Task
data