Vishakha Nagpal
Vishakha Nagpal

Reputation: 19

How to use Abort Controller to abort APIs initiated from inside useEffect but triggered by user action?

  1. I am calling some set of APIs inside the useEffect hook.
  2. But incase user clicks on the cancel button. I want controller.abort() to trigger to cancel all API calls (let's call this method as *cancelAllCalls*())

Problems : (1) I have to initiate controller.abort() outside useEffect. >> This required controller variable to be accessible inside *cancelAllCalls()* - Not working

(2) If I try to do a setState inside *cancelAllCalls()* and add that as a dependency in the useEffect to call controller.abort()it will still re-initiate the controller and the signal passed to the APIs will also change - Not working

Note : I am able to achieve it by adding an eventListner on by cancel button inside the useEffect only (& I made sure it happens only once by using a flag) and then calling controller .abort() inside it. But I am not quite contented with this approach.

Any suggestions/guidance here?

Upvotes: 1

Views: 3355

Answers (1)

Dmitriy Mozgovoy
Dmitriy Mozgovoy

Reputation: 1597

You can do something like this:

function TestComponent(props) {
  const ref = React.useRef(null);
  
  React.useEffect(() => {
    ref.current= new AbortController;
    return () => (ref.current.abort());
  }, []);

  const cancelAllCalls= ()=>{
    ref.current.abort();
    ref.current= new AbortController();
  }

  // your hooks
  React.useEffect(() => {
     //..
  }, [myVar])

  return ()
}

Or like this (Live Demo):

import React from "react";
import { useAsyncEffect } from "use-async-effect2";
import cpAxios from "cp-axios";

// Note: the related network request will also be aborted

function TestComponent(props) {
  const [cancel, done, result, err] = useAsyncEffect(
    function* () {
      return (yield cpAxios(props.url).timeout(props.timeout)).data;
    },
    { states: true, deps: [props.url] }
  );

  return (
    <div>
      <div>
        {done ? (err ? err.toString() : JSON.stringify(result)) : "loading..."}
      </div>
      <button onClick={cancel} disabled={done}>
        Cancel async effect
      </button>
    </div>
  );
}

Upvotes: 5

Related Questions