How to Effectively Cancel APIs in Next.js with Abort Controller

Jay PatelJay Patel
4 min read

Hey there! Today, I want to share a little journey I recently had while working with APIs in Next.js. If you’ve ever found yourself tangled up in API calls, especially when building a web app, you’ll know how important it is to manage those calls efficiently. So, let’s dive into how I learned to cancel API requests using the Abort Controller and useRef.

The Frustration of Unwanted Requests

Not too long ago, I was building a feature with multiple user input fields—text fields, dropdowns, and file uploads. Each time a user interacted with these fields (like on the onBlur event), I needed to make an API call to fetch updated data.

Every time a user made a change, my component would flood the server with requests. It became clear that I needed a way to cancel all ongoing API calls except for the most recent one. That’s when I stumbled upon the Abort Controller and realized I could use useRef to manage it effectively.

What is an Abort Controller?

At first, the term “Abort Controller” sounded a bit intimidating. But once I dug deeper, it became clear that it’s a simple yet powerful tool for managing fetch requests in JavaScript. The Abort Controller allows you to cancel requests that are no longer needed, making it ideal for scenarios where components unmount, users navigate away, or when handling rapid input changes like search suggestions. It helps keep your app responsive and reduces unnecessary network traffic.

Implementing Abort Controller with useRef in Next.js

Let me walk you through how I integrated the Abort Controller into my Next.js application using useRef. Here’s a simple breakdown of the steps:

  1. Creating the Controller: When you start your fetch request, create an instance of AbortController and store it in a ref. This allows you to maintain a single controller instance throughout the component's lifecycle, ensuring that you can manage ongoing requests effectively. By using useRef, you avoid unnecessary re-renders that could occur if you use state.

  2. Using the Signal: Pass the signal from the controller to your fetch request. This signal acts as a communication channel between your fetch operation and the AbortController, enabling the fetch request to listen for any abort events. If the abort method is called, the fetch request will be canceled, preventing any further processing or resource usage.

  3. Handling Cleanup: In the onBlur event handler, abort any ongoing requests before making a new one.

Here’s a snippet of code that illustrates this:

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

const WeatherComponent = () => {
  const controllerRef = useRef(null);
  const [weatherData, setWeatherData] = useState(null);
  const [error, setError] = useState(null);

  const fetchData = async (inputValue) => {
    // Check for any ongoing requests and abort them
    if (controllerRef.current) {
      controllerRef.current.abort();
    }
    // Create a new controller for this request
    controllerRef.current = new AbortController();
    const signal = controllerRef.current.signal;

    try {
      const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${inputValue}&appid=ur-api-key&units=metric`, { signal });
      if (!response.ok) {
        throw new Error('City not found');
      }
      const data = await response.json();
      setWeatherData(data);
      setError(null);
    } catch (error) {
      if (error.name === 'AbortError') {
        console.log('Fetch aborted');
      } else {
        setError(error.message);
        console.error('Fetch error:', error);
      }
    }
  };

  const handleBlur = (event) => {
    const inputValue = event.target.value;
    if (inputValue) {
      fetchData(inputValue);
    } else {
      setWeatherData(null);
    }
  };

  useEffect(() => {
    return () => {
      if (controllerRef.current) {
        controllerRef.current.abort();
      }
    };
  }, []);

  return (
    <div className="container">
      <input type="text" onChange={handleBlur} placeholder="Enter city name..." />
      {error && <p className="error-message">{error}</p>}
      {weatherData && (
        <div className="weather-info">
          <h2>Weather in {weatherData.name}</h2>
          <p>Temperature: {weatherData.main.temp} °C</p>
          <p>Condition: {weatherData.weather[0].description}</p>
        </div>
      )}
    </div>
  );
};

export default WeatherComponent;

P.S.: For demonstration purposes, I utilized the onChange event and implemented a throttling effect to simulate a 3G network speed.

Reflecting on My Experience and Final Thoughts

Integrating the Abort Controller into my project was like discovering the last piece of a puzzle. It streamlined my requests and made the app feel much more responsive. As developers, we often complicate things when a simple tool like the Abort Controller can do the trick.

Have you ever struggled with multiple API calls or slow performance? By using the Abort Controller with useRef, you can boost your app's efficiency. So, next time you're working with APIs in Next.js, keep this handy tip in mind—you'll have more time to create cool features instead of fixing endless requests.

Thanks for reading! If you have any questions or want to share your own API experiences, drop a comment below!

0
Subscribe to my newsletter

Read articles from Jay Patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jay Patel
Jay Patel

I'm a software engineer who loves bringing ideas to life through code. When I'm not coding, I'm busy dreaming up my next big idea! When I finally take a break, you can find me having long conversations with my friends.