Polling in React
Tags: javascript, react, webdev, programming
Published: 2024-06-09 22:37:18

In today's tech space of web development, real-time data updates are important for creating engaging and responsive user experiences. Whether you're building a dashboard, a chat application, a server interface, or a stock trading platform, you often need to check the status of a server or a process at regular intervals. This process is known as polling, and it's a common technique used over socket connections.

Just before we see how Polling works, we should identify Why Polling?

We can describe polling as a straightforward approach to fetching data from the server periodically. Unlike more advanced techniques like WebSocket or Server-Sent Events (SSE), polling doesn't require complex setup or server-side configurations which makes it a reliable way to get the job done, especially in scenarios where you need to retrieve data from a third-party API or a legacy system that doesn't support real-time updates.

A good sample where polling can be useful will be:

When building a weather application that displays the current temperature, humidity, and wind speed for a specific location. You might want to poll the weather API every 5 minutes to ensure that your users have access to the latest weather information.

We can also use polling when we want to support older browsers or have limited server resources, and we can't utilize WebSocket for real-time chat.

Let's briefly look at how we can use Polling in React: 

In our problem statement let's assume we have a web application where users can start and stop a server (e.g. something like npm run dev or python manage.py runserver). We want to provide real-time feedback on the server status whether it's running, creating, or stopping. Polling is an effective way to achieve this.

```
const pollingFunc = async () => {
   //fetch server data
  const data = await fetchServerData("GET");

  switch (data?.status) {
    case "stopped":
      setStatus({ stopped: true });
      break;

    case "running":
      if (data?.url) {
        setData(data);
        setStatus({ running: true });
        toast.success("Server is running");
      }
      break;

    case "creating":
      setStatus({ creating: true });
      break;

    case "stopping":
      setStatus({ stopping: true });
      break;

    default:
      handleError(data)
	toast.error(`An error occured, ${data.error_message}`)
      break;
  }
};
```
Addressing the asynchronous pollingFunc above, it fetches data from the server using the fetchServerData function. Based on the server's response, different cases are handled, such as updating the application state, displaying toast notifications, or stopping the polling process.

The key to implementing polling in React is to use the setInterval function, which allows you to execute a function repeatedly at a specified interval. Here's an example of how you might use setInterval to call the pollingFunc every 5 seconds:

```
import React, { useEffect, useRef } from 'react';

const MyComponent = () => {
  const pollingRef = useRef(null);
  useEffect(() => {
    const startPolling = () => {
      pollingRef.current = setInterval(() => {
        pollingFunc();
      }, 5000); // Poll every 5 seconds
    };
    startPolling();

    return () => {
      clearInterval(pollingRef.current);
    };
  }, []);
};
```
We utilize the useRef hook to create a mutable(changeable) reference to the interval ID returned by setInterval. This allows us to clear the interval when the component unmounts, preventing memory leaks. The useEffect hook is used to start the polling process when the component mounts. The startPolling function initializes the interval and calls pollingFunc every 5 seconds. The cleanup function returned by useEffect ensures that the interval is cleared when the component unmounts.

And that's how polling works, quite straightforward no tweaks or headaches, but one important consideration when implementing polling in React is how to update the component's state. Updating states within the polling function would leave you wondering what's wrong with my code? and this is because our setInterval runs in a different event loop. The setInterval callback captures the state at the time it was created and does not reflect subsequent updates to the state, so at that instance, our state doesn't know about any update. To handle this situation effectively, one can use a Ref Hook to keep track of the latest state OR manage the state updates within a useEffect. Another approach is to pass the state and the setState function as parameters to the polling function.

Let's update our above example to include the stopping state:

```
const pollingFunc = async (stoppingState: boolean) => {

  switch (data?.status) {
    case "stopped":
      setStatus({ stopped: true });
      if (stoppingState) {
        toast.success("Server stopped");
      }
      setStatus({ ...defaultState });
// let's assume we have a defaultState of all possible 
// status to be false here, so we can just spread it
      break;
   // we have the same prev code as earlier
}
```

```
//Updating our UseEffect

const MyComponent = () => {
  const pollingRef = useRef(null);
  useEffect(() => {
    const startPolling = (stoppingState) => {
      pollingRef.current = setInterval(() => {
        pollingFunc(stoppingState);
      }, 5000); // Poll every 5 seconds
    };

    startPolling(false);

    return () => {
      clearInterval(pollingRef.current);
    };

  }, []);
};
```
Just to display this in action let's create a stopServer function

```
const stopServer = async () => {
  setStatus({ ...status, loading: true });
  await fetchServerData("DELETE");
  setStatus({ ...status, loading: false, stopping: true });
  setData(null);
  startPolling(true);
};
```
Implementing polling in React is a straightforward approach to fetching data from the server at regular intervals. However, it's essential to consider the appropriate scenarios and the potential implications of polling on performance, server load, and user experience.

Depending on the problem at hand, we can figure out the best and cleanest way to handle polling. In cases where real-time updates are crucial, and server resources are available, utilizing WebSocket might be a better choice as they establish a bidirectional communication channel between the client and the server, allowing for efficient and immediate data updates without the need for continuous polling.

It's important to remember that as software engineers, we need to take into account the best tool for the job at the right time. Polling is a valuable technique, but it's not a one-size-fits-all solution. Carefully evaluate your application's requirements, performance needs, and server resources before deciding on the appropriate approach for handling real-time data updates.

Please share your thoughts, experiences, and any additional insights you might have on implementing polling or alternative approaches to real-time data updates in React applications. Also, stay tuned to see how we would implement polling in Angular.