# Recipes
Each recipe starts work outside an effect and cleans it up on unmount. For work inside `useEffect`, see [Inside useEffect](../README.md#inside-useeffect).
Fetch from an event handler
```jsx
import { useState } from 'react';
import { useAbortSignal } from 'use-is-mounted-ref';
function Search() {
const signal = useAbortSignal();
const [results, setResults] = useState([]);
const search = async (query) => {
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`, { signal });
setResults(await res.json());
} catch (err) {
if (err.name !== 'AbortError') throw err;
}
};
return search(e.target.value)} />;
}
```
On unmount, the request aborts and `setResults` never runs.
Listeners added from a handler
Pass the signal to `addEventListener`. The browser removes the listener on abort, so you skip `removeEventListener`.
```jsx
import { useAbortSignal } from 'use-is-mounted-ref';
function Draggable({ onMove }) {
const signal = useAbortSignal();
const startDrag = () => {
window.addEventListener('pointermove', onMove, { signal });
};
return
Drag me
;
}
```
Timers started from a handler
```jsx
import { useAbortSignal } from 'use-is-mounted-ref';
function Toast({ onClose }) {
const signal = useAbortSignal();
const scheduleClose = () => {
const id = setTimeout(onClose, 3000);
signal.addEventListener('abort', () => clearTimeout(id), { once: true });
};
return ;
}
```
Abort on unmount or after a timeout
`AbortSignal.any` combines signals. The request stops on whichever comes first.
```jsx
const signal = useAbortSignal();
const load = () => fetch('/api/slow', { signal: AbortSignal.any([signal, AbortSignal.timeout(5000)]) });
```
Check [browser support](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static) before relying on it.