'Get query response time/duration in react-query

I am using react-query's useQuery

I need to know how much time elapsed between when the query was sent and when the query settled.

I can't find my way using the return type or params of useQuery

It's not for debugging purposes but for functional purposes (debugger doesn't help here)



Solution 1:[1]

Here's a complete example which includes a custom hook for measuring the duration that each query is in the "loading" state. It includes some comments, and I can explain further if anything is unclear.

TS Playground

body { font-family: sans-serif; }
<div id="root"></div><script src="https://unpkg.com/[email protected]/umd/react.development.js"></script><script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script><script src="https://unpkg.com/[email protected]/dist/react-query.development.js"></script><script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script><script>Babel.registerPreset('tsx', {presets: [[Babel.availablePresets['typescript'], {allExtensions: true, isTSX: true}]]});</script>
<script type="text/babel" data-type="module" data-presets="tsx,react">

// Adapted from https://react-query.tanstack.com/overview#enough-talk-show-me-some-code-already

// import ReactDOM from 'react-dom';
// import { default as React, useEffect, useMemo, useRef, useState } from 'react';
// import { QueryClient, QueryClientProvider, useQuery, type UseQueryResult } from 'react-query';

// This Stack Overflow snippet demo uses UMD modules instead of the above import statments
const { useEffect, useMemo, useRef, useState } = React;
const { QueryClient, QueryClientProvider, useQuery } = ReactQuery;

const queryClient = new QueryClient();

async function fetchGitHubRepoData (user: string, repo: string) {
  return (await fetch(`https://api.github.com/repos/${user}/${repo}`)).json();
}

function fetchRepoReactQuery () {
  return fetchGitHubRepoData('tannerlinsley', 'react-query');
};

function delay (ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// This one will always be > 2000ms
async function fetchRepoTypeScript () {
  const data = fetchGitHubRepoData('microsoft', 'TypeScript');
  await delay(2000);
  return data;
}

/**
 * Get duration of current query in milliseconds
 * Returns `Infinity` while loading
 */
function useQueryTime (queryKey: string, status: UseQueryResult['status']): number {
  const lastKeyRef = useRef('__initial');
  const [interval, setInterval] = useState<[begin: number, end: number]>([0, Infinity]);

  return useMemo(() => {
    if (lastKeyRef.current !== queryKey) {
      lastKeyRef.current = queryKey;
      setInterval([0, Infinity]);
    }

    const [begin, end] = interval;

    if (begin === 0 && status === 'loading') {
      setInterval(([, end]) => [performance.now(), end]);
    }

    if (!Number.isFinite(end) && ['error', 'success'].includes(status)) {
      setInterval(([begin]) => [begin, performance.now()]);
    }

    return end - begin;
  }, [interval, status, queryKey]);
}

function Example() {
  const [[queryKey, queryFn], setQueryKeyAndFn] = useState<[string, () => Promise<any>]>(['react-query', fetchRepoReactQuery]);

  const { isLoading, error, data, status } = useQuery(queryKey, queryFn);
  const queryTime = useQueryTime(queryKey, status);

  useEffect(() => {
    // Change query after 2 seconds:
    setTimeout(() => setQueryKeyAndFn(['TypeScript', fetchRepoTypeScript]), 2000);
  }, [setQueryKeyAndFn]);

  const queryInfoNode = (
    <div>
      <h2>Query time: {isLoading ? 'still loading' : `${queryTime} ms`}</h2>
    </div>
  );

  if (isLoading) return (<div>{queryInfoNode}'Loading...'</div>);
  if (error) return (<div>{queryInfoNode}'An error has occurred: ' + error.message</div>);

  return (
    <div>
      {queryInfoNode}
      <h2>{data.name}</h2>
      <p>{data.description}</p>
      <strong>? {data.subscribers_count}</strong>{' '}
      <strong>? {data.stargazers_count}</strong>{' '}
      <strong>? {data.forks_count}</strong>
    </div>
  )
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Example />
    </QueryClientProvider>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));

</script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jsejcksn