reactjscachingfetch-apireact-querytanstackreact-query

How to parse data received from TanStack Query (React Query) to keep it in cache?


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.


Solution

  • 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>
      );
    }
    

    Demo

    Edit how-to-parse-data-received-from-tanstack-query-react-query-to-keep-it-in-cache