hooks
useAbortController

useAbortController

A custom hook for managing operations with an AbortController instance.

Add hook

Create a file use-abort-controller.ts and copy & paste the code from useAbortController.

Hook

import { useRef, useState } from 'react'
 
export const useAbortController = (controller: AbortController) => {
    if (!controller) {
        throw new Error('AbortController instance is required. Make sure to provide a valid AbortController.')
    }
 
    const [isAborted, setIsAborted] = useState(false)
 
    const controllerRef = useRef(controller)
 
    const getSignal = () => {
        return controllerRef.current.signal
    }
 
    const abort = () => {
        controllerRef.current.abort()
        setIsAborted(true)
    }
 
    const abortAfter = (time: number) => {
        setTimeout(() => {
            abort()
        }, time)
    }
 
    const abortIf = (fn: (arg?: unknown) => unknown) => {
        if (fn()) {
            abort()
        }
    }
 
    const abortIfAfter = (fn: (arg?: unknown) => unknown, time: number) => {
        if (fn()) {
            abortAfter(time)
        }
    }
 
    return {
        getSignal,
        abort,
        abortAfter,
        abortIf,
        abortIfAfter,
        isAborted,
    }
}
 

Usage

 
import { useEffect, useState } from 'react'
import { useAbortController } from './hooks/use-abort-controller'
 
const App = () => {
 
   const abortController = new AbortController()
 
   const [product, setProduct] = useState<any | null>(null)
 
   const { abort, isAborted, getSignal } = useAbortController(abortController)
 
   const signal = getSignal()
 
   const fetchData = async () => {
       try {
           const response = await fetch('https://fakestoreapi.com/products/1', { signal })
           const data = await response.json()
           setProduct(data)
       } catch (error) {
           if (error instanceof Error) {
               if (error.name === 'AbortError') {
                   console.log('Fetch aborted')
               } else {
                   console.error('Error fetching data:', error)
               }
           }
       } finally {
           console.log(signal.aborted)
       }
   }
 
   useEffect(() => {
       fetchData()
   }, [signal])
 
   const handleAbortClick = () => {
       abort()
   }
 
   const abortStatus = isAborted ? 'You canceled your request' : 'We are processing your request ...'
 
   const requestStatus = product ? product.title : abortStatus
 
   return (
       <div
           style={{
               display:"flex",
               flexDirection:"column",
               alignItems:"center",
               position: 'absolute',
               top: '20%',
               left: '45%',
               width: 'auto',
           }}
       >
           <p>{requestStatus}</p>
           {product || isAborted ? null : (
               <button onClick={handleAbortClick} style={{ marginTop: 20 }}>
                   Cancel
               </button>
           )}
       </div>
   )
}
 
export default App
 
 

API

Parameters

NameTypeDescription
controllerAbortControllerThe AbortController instance to manage operations.

Returns

NameDescription
getSignal(): AbortSignalRetrieves the AbortSignal associated with the provided controller.
abort(): voidAborts the associated operation.
abortAfter(time: number): voidAborts the associated operation after a specified delay.
abortIf(fn: (arg?: unknown) => unknown): voidAborts the operation if the provided condition is met.
abortIfAfter(fn: (arg?: unknown) => unknown, time: number): voidAborts the operation if the provided condition is met after a specified delay.
isAborted: booleanA boolean state indicating whether the operation has been aborted.

Contributors

Avatar 1