There are often times in a web application where you need to send a request for the latest user interaction. We need a way to prevent subsequent (async) logic from running for all but the most recent request 鈥撀爏omething like Axios' cancel token or fetch()'s AbortController.
The hardest part about this is that every library has its own API. You can pass a controller to the fetch function but there鈥檚 no general way to do it inside SWR. And another question is when to cancel it (when unmounting a component?).
I think it鈥檚 way easier to ignore the result than cancel it with the current state of fetching libraries
For now a custom hook can (partially) solve it:
function useCancelableSWR (key, opts) {
const controller = new AbortController()
return [useSWR(key, url => fetch(url, { signal: controller.signal }), opts), controller]
}
// to use it:
const [{ data }, controller] = useCancelableSWR('/api')
// ...
controller.abort()
(also mentioned in #159)
You probably don't want to memoize the AbortController.
You can only abort a controller instance once, so a new request requires a new controller.
Another thing to note is that useMemo is a performance optimization with no hard guarantee that it won't be recalculated. React can choose to recalculate memoized values (https://reactjs.org/docs/hooks-reference.html#usememo).
@strothj The issue is not whether the AbortController instance is properly cached or not. The abort controller should not be cached at all.
I did this with axios
function useCancellableSWR(key, swrOptions) {
const source = axios.CancelToken.source();
return [
useSWR(key, (url) => axios.get(url, { cancelToken: source.token }).then(res => res.data), {
...swrOptions,
}),
source,
];
}
// usage:
const [{ data }, cancelFn] = useCancellableSWR('/endpoint');
cancelFn.cancel()
Most helpful comment
For now a custom hook can (partially) solve it:
(also mentioned in #159)