0

I watch tutorial about React and didnt understand how AbortController works.

useEffect(() => {
    const abortCont = new AbortController();

    setTimeout(() => 
        {fetch(url, { signal: abortCont.signal })
            .then(res => {
                if(!res.ok) {
                    throw Error('could not fetch the data from that resource');
                }
                return res.json();
            })
            .then(data => {
                setData(data);
                setIsPending(false);
                setError(null);
            })
            .catch((err) => {
                if (err.name == 'AbortError'){
                    console.log('fetch aborted');
                }
                else {
                    setIsPending(false);
                    setError(err.message);
                }                   
        })}, 1000);

        return () => abortCont.abort();
}, [url]);

why he uses return and why this code works when abort didnt happen if I call abort() anyway

kanamagg
  • 33
  • 4

3 Answers3

4

AbortController is used to cancel the HTTP request initiated using the fetch API.

Function returned from the callback function of useEffect hook is a cleanup function that executes:

  • before the component unmounts
  • before running the useEffect again

Calling .abort() method from the cleanup function will cancel the HTTP request and prevent your code from updating the state of an unmounted component.

If your code tries to update the state of an unmounted component, React will give you a warning:

Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.

For details on cleanup function of useEffect hook, visit: React Docs - Effects with Cleanup

Yousaf
  • 27,861
  • 6
  • 44
  • 69
2

...why he use return...

I assume you're asking about the return () => abortCont.abort();. When you return a function from useEffect, React will call that function when something has changed (url in this case, although React can also do it for its own purposes) and it's about to remove the component, re-render it, and then call the useEffect callback again. So since url is changing, it makes sense to return a function that will abort the fetch (if it hasn't already happened).

...and why this code works when abort doesnt happend if I call abort() anyway..."*

If React calls that function before fetch has finished its work, fetch will abort the fetch operation. If you're not seeing that, it's because fetch is already done by the time abort() is called. More about that: AbortController, fetch.

You probably also want to add a check on abortCont.signal.aborted in at least he first fulfillment handler:

useEffect(() => {
    const abortCont = new AbortController();

    setTimeout(() => 
        {fetch(url, { signal: abortCont.signal })
            .then(res => {
                if(!res.ok) {
                    throw Error('could not fetch the data from that resource');
                }
                return res.json();
            })
            .then(data => {
                // ***
                if (abortCont.signal.aborted) {
                    const e = new Error("Fetch cancelled");
                    e.name = "AbortError";
                    throw e;
                }
                setData(data);
                setIsPending(false);
                setError(null);
            })
            .catch((err) => {
                if (err.name == 'AbortError'){
                    // *** It seems odd that `isPending` isn't cleared here
                    console.log('fetch aborted');
                }
                else {
                    setIsPending(false);
                    setError(err.message);
                }                   
        })}, 1000);

        return () => abortCont.abort();
}, [url]);

It isn't required, but it means that if the fetch finishes before abort() was called but the fulfillment handler hasn't been called yet, you catch that and don't continue your logic.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

AbortController is used for aborting Fetch Requests and it's a browser built-in feature. You can refer to this beautiful article as it'll help you understand deeper with practical examples.

https://davidtang.io/2020-02-20-aborting-fetch-requests/

Blessing
  • 2,450
  • 15
  • 22