16

When I refetch my query it goes into 'Updating ...' state when I have a onClick button but I want the query to refetch and show the 'Loading ...' state. My code is:

https://stackblitz.com/edit/react-ts-jfq8ve?file=index.tsx

import React, { useEffect } from 'react';
import { render } from 'react-dom';
import { useQuery } from 'react-query';
import axios from 'axios';
import { QueryClient, QueryClientProvider } from 'react-query';

const App: React.FunctionComponent = () => {
  const [value, setValue] = React.useState<number>(7);

  const queryKey = 'getData';

  const getData = async (): Promise<any> => {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const response = await axios
      .get(`https://jsonplaceholder.typicode.com/todos`)
      .then((res) => res.data);
    return response;
  };

  const {
    data: result,
    status,
    isRefetching,
    error,
    refetch,
  }: any = useQuery(queryKey, getData, {
    refetchOnWindowFocus: true,
    staleTime: 0,
    cacheTime: 0,
    refetchInterval: 0,
  });

  useEffect(() => {
    refetch();
  }, [value, refetch]);

  return (
    <div className="Container">
      <button onClick={() => setValue(prevValue => prevValue + 1 )}>Set value</button>
      {isRefetching ? <p className="mt-3">Updating data...</p> : null}
      {status === 'error' && <div className="mt-5">{error.message}</div>}
      {status === 'loading' && <div className="mt-5">Loading data ...</div>}
      {status === 'success' && (
        <div>
          {result?.map((inner: any, index: number) => {
            return <li key={index}>{inner.title}</li>;
          })}
        </div>
      )}
    </div>
  );
};

const queryClient = new QueryClient();

render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('root')
);

3 Answers 3

15

Based on Yozi's answer, I removed useEffect and just put refetch function to onClick of the button.

  const {
    data: result,
    isFetching,
    status,
    error,
    refetch,
  }: any = useQuery(queryKey, getData, {
    refetchOnWindowFocus: true,
    staleTime: 0,
    cacheTime: 0,
    refetchInterval: 0,
  });

  return (
    <div className="Container">
      <button onClick={refetch}>Refetch query</button>
      {status === 'error' && <div className="mt-5">{error.message}</div>}
      {isFetching ? (
        <div className="mt-5">Loading data ...</div>
      ) : (
        <div>
          {status === 'success' && (
            <div>
              {result?.map((inner: any, index: number) => {
                return <li key={index}>{inner.title}</li>;
              })}
            </div>
          )}
        </div>
      )}
    </div>
  );
};

Online example at: https://stackblitz.com/edit/react-ts-j87pub?file=index.tsx

Sign up to request clarification or add additional context in comments.

1 Comment

this is so awesome i can go to sleep now
4

status === loading

if the query is in a "hard" loading state. This means there is no cached data, and the query is currently fetching...

I guess you do not need to use status === loading for your particular case. Use isFetching - it covers both initial loading and refetching


import React, { useEffect } from 'react';
import { render } from 'react-dom';
import { useQuery } from 'react-query';
import axios from 'axios';
import { QueryClient, QueryClientProvider } from 'react-query';

const App: React.FunctionComponent = () => {
  const [value, setValue] = React.useState<number>(7);

  const queryKey = 'getData';

  const getData = async (): Promise<any> => {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const response = await axios
      .get(`https://jsonplaceholder.typicode.com/todos`)
      .then((res) => res.data);
    return response;
  };

  const {
    data: result,
    status,
    isFetching,
    error,
    refetch,
  }: any = useQuery(queryKey, getData, {
    refetchOnWindowFocus: true,
    staleTime: 0,
    cacheTime: 0,
    refetchInterval: 0,
  });

  useEffect(() => {
    refetch();
  }, [value, refetch]);

  return (
    <div className="Container">
      <button onClick={() => setValue(prevValue => prevValue + 1 )}>Set value</button>
      {status === 'error' && <div className="mt-5">{error.message}</div>}
      {isFetching && <div className="mt-5">Loading data ...</div>}
      {status === 'success' && (
        <div>
          {result?.map((inner: any, index: number) => {
            return <li key={index}>{inner.title}</li>;
          })}
        </div>
      )}
    </div>
  );
};

const queryClient = new QueryClient();

render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('root')
);


1 Comment

How would that be implemented changed based on the above code?
0

isFetching did it for me. I had to change status === "pending" to isFetching and then render the relevant component. Example below:

{(isFetching) ? <SkeletonComponent /> : <> Some component</> }

Then use query invalidation to manually trigger the refresh based on some mutations.

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.