React: How to prevent unnecessary api calls

In React applications, it’s common to have buttons triggering HTTP requests. However, a challenge arises when users rapidly click the same button, potentially leading to multiple redundant API calls. In this blog post, we’ll explore strategies to avoid making duplicate HTTP requests using the JSONPlaceholder API as a real-world example.

The Problem: Duplicate Requests

Consider a scenario where you have a button that fetches user data from the JSONPlaceholder API when clicked. Without any precautionary measures, users might click the button multiple times in quick succession, resulting in redundant API calls.

Example: Fetching User Data

import React, { useState } from 'react';

const UserFetcher = () => {
  const [userData, setUserData] = useState(null);

  const fetchUserData = async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
      const data = await response.json();
      setUserData(data);
    } catch (error) {
      console.error('Error fetching user data:', error);
    }
  };

  return (
    <div>
      <button onClick={fetchUserData}>Fetch User Data</button>
      {userData && (
        <div>
          <h2>{userData.name}</h2>
          <p>Email: {userData.email}</p>
          {/* Display other user data */}
        </div>
      )}
    </div>
  );
};

export default UserFetcher;

In this example, the fetchUserData function is triggered when the button is clicked, fetching user data from the JSONPlaceholder API. However, if the user clicks the button rapidly, it may result in unnecessary API calls.

Solution 1: Disable Button During Request

One simple solution is to disable the button while the API request is in progress, preventing users from triggering multiple requests simultaneously.

Example: Disabling Button

// ... (imports and component definition)

const UserFetcher = () => {
  const [userData, setUserData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const fetchUserData = async () => {
    try {
      setIsLoading(true);
      const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
      const data = await response.json();
      setUserData(data);
    } catch (error) {
      console.error('Error fetching user data:', error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <button onClick={fetchUserData} disabled={isLoading}>
        {isLoading ? 'Fetching...' : 'Fetch User Data'}
      </button>
      {userData && (
        <div>
          <h2>{userData.name}</h2>
          <p>Email: {userData.email}</p>
          {/* Display other user data */}
        </div>
      )}
    </div>
  );
};

export default UserFetcher;

By introducing the isLoading state, we can disable the button when a request is in progress. This prevents users from triggering multiple requests simultaneously and ensures that the button is only clickable when the API call is complete.

Solution 2: Throttle or Debounce User Clicks

Another approach is to use a debounce or throttle function to limit the frequency of API calls. This prevents multiple rapid clicks from triggering separate requests.

Using Lodash for Debouncing

npm install lodash

Example: Debouncing Clicks

import React, { useState } from 'react';
import _ from 'lodash';

const UserFetcher = () => {
  const [userData, setUserData] = useState(null);

  // Debounce the fetchUserData function to limit rapid clicks
  const debouncedFetchUserData = _.debounce(async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
      const data = await response.json();
      setUserData(data);
    } catch (error) {
      console.error('Error fetching user data:', error);
    }
  }, 1000); // 1000ms debounce time

  return (
    <div>
      <button onClick={debouncedFetchUserData}>Fetch User Data</button>
      {userData && (
        <div>
          <h2>{userData.name}</h2>
          <p>Email: {userData.email}</p>
          {/* Display other user data */}
        </div>
      )}
    </div>
  );
};

export default UserFetcher;

In this example, the debouncedFetchUserData function is created using the debounce function from lodash. This function ensures that the original function (fetchUserData) is only called after a specified delay (in this case, 1000ms). Rapid clicks within this time frame won’t trigger additional API requests.

Conclusion

Effectively handling multiple clicks on the same button in a React application is crucial to optimizing performance and resource usage. By either disabling the button during the request or employing a debounce mechanism, you can prevent redundant API calls and provide a smoother user experience. Choose the approach that best fits your application’s requirements and complexity. Happy coding!

Next Post Previous Post
No Comment
Add Comment
comment url