Search code examples
reactjsreact-componentuse-effect

Undo API call after component destroy


I do API call on component mount using useEffect and depend of response do some state changes, but what if my component destroys while request is in pending status, how can I undo this request and all functions that try to change my state on success


Solution

  • So using fetch you can do like this as shown below, you can user native abort in js

    you can read more on here

    import React, { useState, useEffect } from "react";
    import ReactDOM from "react-dom";
    import { BrowserRouter, Route, Switch, Link } from "react-router-dom";
    
    import "./styles.css";
    
    const Home = () => {
      const [data, setData] = useState([]);
      const [isLoading, setIsLoading] = useState(false);
      const [errorMessage, setErrorMessage] = useState(null);
    
      useEffect(() => {
        const abortController = new AbortController();
    
        const getData = async () => {
          try {
            setIsLoading(true);
            const response = await fetch(
              "https://jsonplaceholder.typicode.com/comments",
              {
                method: "get",
                headers: {
                  Accept: "application/json",
                  "Content-Type": "application/json"
                },
                signal: abortController.signal
              }
            );
    
            if (response.ok) {
              const body = await response.json();
              setData(body);
              setIsLoading(false);
              return;
            }
            const customError = {
              message: "Some Error Occured"
            };
            throw customError;
          } catch (error) {
            console.log(error.name);
            setIsLoading(false);
            if (error.name === "AbortError") {
              setErrorMessage("Request has aborted");
              return;
            }
            setErrorMessage("Internal server error");
          }
        };
    
        getData();
        return () => {
          abortController.abort();
        };
      }, []);
    
      return (
        <>
          {isLoading && <span>Loading Data, Please wait...</span>}
          {errorMessage && <span>{errorMessage}</span>}
          {data.length > 0
            ? data.map(d => {
                return <p key={d.id}>{d.name}</p>;
              })
            : null}
        </>
      );
    };
    
    const Products = () => <>Products</>;
    
    function App() {
      return (
        <BrowserRouter>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/products">Products</Link>
            </li>
          </ul>
          <Switch>
            <Route exact path="/" component={Home} />
            <Route exact path="/products" component={Products} />
          </Switch>
        </BrowserRouter>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    Working codesandbox

    Note: You need to open the dev tools and make the network tab throttling to slow 3g from online and open the console so when clicking on the products link the api will get cancelled.

    I hope this will give a better view of this problem

    happy coding :)