実際は両者でエラーのクラスを分けたが、だいたいこんな感じ。
import { useRef, useEffect } from 'react' export default function useFetch() { const abortsRef = useRef({}) function fetchFoo() { return requestWithAbort(signal => fetch('/foo', { signal })) } function fetchBar() { return requestWithAbort(signal => fetch('/bar', { signal })) } function requestWithAbort(request) { const abortController = new AbortController() return new Promise((resolve, reject) => { const timeout = setTimeout(() => { abortsRef.current[timeout].abort() delete abortsRef.current[timeout] }, 1000 * 60) abortsRef.current[timeout] = abortController request(abortController.signal).then(r => { resolve(r) }).catch(e => { reject(e) }).finally(() => { clearTimeout(timeout) delete abortsRef.current[timeout] }) }) } useEffect(() => { return () => { Object.values(abortsRef.current).forEach(c => c.abort()) } }, []) return { fetchFoo, fetchBar } }