Interval fetching with react-query
Tags: react, reactquery, javascript, webdev
Published: 2021-02-28 02:54:20

<span>Photo by <a href="https://unsplash.com/@emilymorter?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Emily Morter</a> on <a href="https://unsplash.com/s/photos/data?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>

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](https://react-query.tanstack.com/) 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.

```javascript
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);
    },
  });
};
```

For the interval fetching query part, we are going to take advantage of the [refetchInterval](https://react-query.tanstack.com/reference/useQuery) method we have with react-query.

```javascript
//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,
  });
```

Finally we end up with the final hook.

```javascript
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 };

};
```

And we can use it in our component the following way.
```javascript
 const { mutate, data, isLoading } = useProcessInterval({
   onSuccess: () => console.log('Process finished'),
   onError: () => console.log('Error with process'),
 });
```

See you in the next posts! 🖐