DEV Community

loading...
Cover image for Interval fetching with react-query

Interval fetching with react-query

Allan López
Updated on ・2 min read

Photo by Emily Morter on Unsplash

Recently I was asked to implement a page that needs to work with a fetching interval, as I wanted to keep the server state as simple as posible I decided to give react-query a try and implement a interval logic on it. Here is what I came up with it.

Use case

We need to make a post to an endpoint to start a process. Then every 5 seconds ask for its progress, once we received that the process is finished we must stop fetching.

As a plus I wanted to keep this on a hook in order to be used in different parts of the app. Lets start.🤓

Code

First we need to create a hook with a mutation inside in order to start the process. We add the stop state in order to tell us when to stop the fetching and we save the process id we get from the response.

const useProcessInterval = ({ onSuccess, onError }) => {
  const [processId, setProcessId] = useState(null);
  const [stop, setStop] = useState(false);

  // Mutation to start the process
  const { mutate } = useMutation(startProcess, {
    onMutate: () => {
      //When mutate we want to start fetching
      setStop(false);
    },
    onError: error => {
      console.error(error);
      //Stop fetching
      setStop(true);
      onError();
    },
     onSuccess: data => {
      setProcessId(data.process_id);
    },
  });
};
Enter fullscreen mode Exit fullscreen mode

For the interval fetching query part, we are going to take advantage of the refetchInterval method we have with react-query.

//Fetch until received status is finished
  const { isLoading, data } = useQuery(['processProgress', processId], getProgress, {
    onSuccess: data => {
      if (data.status === 'finished') {
        // Stop fetching
        setStop(true);
        //Clean up processId
        setProcessId(null);
        onSuccess();
      }
    },
    onError: error => {
      console.error(error);
      setStop(true);
      setProcessId(null);
      onError();
    },
    //Only start getting process when we have received the process id from the mutation
    enabled: processId != null,
    //Keep refetching every 5 seconds while we don't stop it
    refetchInterval: stop ? false : 5000,
    refetchIntervalInBackground: true,
    refetchOnWindowFocus: false,
  });
Enter fullscreen mode Exit fullscreen mode

Finally we end up with the final hook.

const useProcessInterval = ({ onSuccess, onError }) => {
  const [processId, setProcessId] = useState(null);
  const [stop, setStop] = useState(false);

  // Mutation to start the process
  const { mutate } = useMutation(startProcess, {
    onMutate: () => {
      setStop(false);
    },
    onError: error => {
      console.error(error);
      setStop(true);
      onError();
    },
     onSuccess: data => {
      setProcessId(data.process_id);
    },
  });

  //Fetch until received status is finished
  const { isLoading, data } = useQuery(['processProgress', processId], getProgress, {
    onSuccess: data => {
      if (data.status === 'finished') {
        setStop(true);
        setProcessId(null);
        onSuccess();
      }
    },
    onError: error => {
      console.error(error);
      setStop(true);
      setProcessId(null);
      onError();
    },
    enabled: processId != null,
    refetchInterval: stop ? false : 5000,
    refetchIntervalInBackground: true,
    refetchOnWindowFocus: false,
  });

  return { mutate, data, isLoading };

};
Enter fullscreen mode Exit fullscreen mode

And we can use it in our component the following way.

 const { mutate, data, isLoading } = useProcessInterval({
   onSuccess: () => console.log('Process finished'),
   onError: () => console.log('Error with process'),
 });
Enter fullscreen mode Exit fullscreen mode

See you in the next posts! 🖐

Discussion (3)

Collapse
tkdodo profile image
Dominik D

Good use-case, thanks for the article. I'd still like to point out that this is not long-polling in an http sense, where the server keeps the connection open until the information is available. What you are doing here is a "normal", traditional polling where the client initiates a new request at an interval level.

see: en.wikipedia.org/wiki/Push_technol...

Maybe you can point that out somewhere, because that is somewhat confusing :)

Collapse
allanloji profile image
Allan López Author

Thanks for the comment, totally agree in changing that to avoid confusion 👍

Collapse
stanislas profile image
Stanislas

Thank you for this!