<p dir="auto">React version: 18.2</p>
<h2 dir="auto">Steps To Reproduce</h2>
<ol dir="auto">
<li>I have multiple async methods that fetch data from API on demand.</li>
<li>This data needs to be loaded initially on page load and also in case of refresh button pressed by the user</li>
<li>Without React.StrictMode the abort controller aborted = false</li>
<li>With React.StrictMode the abort controller gets set to aborted = true</li>
</ol>
<h2 dir="auto">Example code:</h2>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import { useEffect, useState } from &quot;react&quot;;
import axios from &quot;axios&quot;;

export default function App() {
  const [data, setData] = useState([]);
  const [dataLoading, setDataLoading] = useState(false);

  const controller = new AbortController();
  const { signal } = controller;

  const getData = async () =&gt; {
    console.log(&quot;getData API call&quot;);
    setDataLoading(true);
    return axios
      .get(`/api/v1/health`, {
        signal
      })
      .then((res) =&gt; {
        setData([&quot;data: &quot;, &quot;loaded&quot;, &quot; successfully&quot;]);
      })
      .catch((err) =&gt; {
        console.log(&quot;getData caught error&quot;);
        console.log({ err });
      })
      .finally(() =&gt; setDataLoading(false));
  };

  useEffect(() =&gt; {
    getData();

    return () =&gt; {
      console.log(&quot;CONTROLLER ABORT&quot;);
      controller.abort();
    };
  }, []);

  const refreshData = async () =&gt; {
    await getData();
  };

  return (
    &lt;div&gt;
      {data.length ? (
        data.map((val) =&gt; val)
      ) : (
        &lt;div&gt;{dataLoading ? &quot;Loading...&quot; : &quot;Data not found.&quot;}&lt;/div&gt;
      )}
      &lt;Actions onRefresh={refreshData} /&gt;
    &lt;/div&gt;
  );
}

function Actions({ onRefresh }) {
  return (
    &lt;div style={{ marginTop: &quot;20px&quot; }}&gt;
      &lt;button onClick={onRefresh}&gt;Refresh&lt;/button&gt;
    &lt;/div&gt;
  );
}"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-kos">{</span> <span class="pl-s1">useEffect</span><span class="pl-kos">,</span> <span class="pl-s1">useState</span> <span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">"react"</span><span class="pl-kos">;</span>
<span class="pl-k">import</span> <span class="pl-s1">axios</span> <span class="pl-k">from</span> <span class="pl-s">"axios"</span><span class="pl-kos">;</span>

<span class="pl-k">export</span> <span class="pl-k">default</span> <span class="pl-k">function</span> <span class="pl-v">App</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">data</span><span class="pl-kos">,</span> <span class="pl-s1">setData</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-kos">[</span><span class="pl-s1">dataLoading</span><span class="pl-kos">,</span> <span class="pl-s1">setDataLoading</span><span class="pl-kos">]</span> <span class="pl-c1">=</span> <span class="pl-en">useState</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-k">const</span> <span class="pl-s1">controller</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-v">AbortController</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">const</span> <span class="pl-kos">{</span> signal <span class="pl-kos">}</span> <span class="pl-c1">=</span> <span class="pl-s1">controller</span><span class="pl-kos">;</span>

  <span class="pl-k">const</span> <span class="pl-en">getData</span> <span class="pl-c1">=</span> <span class="pl-k">async</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"getData API call"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">setDataLoading</span><span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-k">return</span> <span class="pl-s1">axios</span>
      <span class="pl-kos">.</span><span class="pl-en">get</span><span class="pl-kos">(</span><span class="pl-s">`/api/v1/health`</span><span class="pl-kos">,</span> <span class="pl-kos">{</span>
        signal
      <span class="pl-kos">}</span><span class="pl-kos">)</span>
      <span class="pl-kos">.</span><span class="pl-en">then</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">res</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-s1">setData</span><span class="pl-kos">(</span><span class="pl-kos">[</span><span class="pl-s">"data: "</span><span class="pl-kos">,</span> <span class="pl-s">"loaded"</span><span class="pl-kos">,</span> <span class="pl-s">" successfully"</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
      <span class="pl-kos">}</span><span class="pl-kos">)</span>
      <span class="pl-kos">.</span><span class="pl-en">catch</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">err</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
        <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"getData caught error"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
        <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-kos">{</span> err <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
      <span class="pl-kos">}</span><span class="pl-kos">)</span>
      <span class="pl-kos">.</span><span class="pl-en">finally</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">setDataLoading</span><span class="pl-kos">(</span><span class="pl-c1">false</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">;</span>

  <span class="pl-en">useEffect</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-en">getData</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

    <span class="pl-k">return</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
      <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"CONTROLLER ABORT"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
      <span class="pl-s1">controller</span><span class="pl-kos">.</span><span class="pl-en">abort</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-kos">}</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

  <span class="pl-k">const</span> <span class="pl-en">refreshData</span> <span class="pl-c1">=</span> <span class="pl-k">async</span> <span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-k">await</span> <span class="pl-en">getData</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span><span class="pl-kos">;</span>

  <span class="pl-k">return</span> <span class="pl-kos">(</span>
    <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
      <span class="pl-kos">{</span><span class="pl-s1">data</span><span class="pl-kos">.</span><span class="pl-c1">length</span> ? <span class="pl-kos">(</span>
        <span class="pl-s1">data</span><span class="pl-kos">.</span><span class="pl-en">map</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-s1">val</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-s1">val</span><span class="pl-kos">)</span>
      <span class="pl-kos">)</span> : <span class="pl-kos">(</span>
        <span class="pl-c1">&lt;</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span><span class="pl-kos">{</span><span class="pl-s1">dataLoading</span> ? <span class="pl-s">"Loading..."</span> : <span class="pl-s">"Data not found."</span><span class="pl-kos">}</span><span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
      <span class="pl-kos">)</span><span class="pl-kos">}</span>
      <span class="pl-c1">&lt;</span><span class="pl-ent">Actions</span> <span class="pl-c1">onRefresh</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-en">refreshData</span><span class="pl-kos">}</span> <span class="pl-c1">/</span><span class="pl-c1">&gt;</span>
    <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
  <span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-v">Actions</span><span class="pl-kos">(</span><span class="pl-kos">{</span> onRefresh <span class="pl-kos">}</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  <span class="pl-k">return</span> <span class="pl-kos">(</span>
    <span class="pl-c1">&lt;</span><span class="pl-ent">div</span> <span class="pl-c1">style</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-kos">{</span> <span class="pl-c1">marginTop</span>: <span class="pl-s">"20px"</span> <span class="pl-kos">}</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>
      <span class="pl-c1">&lt;</span><span class="pl-ent">button</span> <span class="pl-c1">onClick</span><span class="pl-c1">=</span><span class="pl-kos">{</span><span class="pl-s1">onRefresh</span><span class="pl-kos">}</span><span class="pl-c1">&gt;</span>Refresh<span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">button</span><span class="pl-c1">&gt;</span>
    <span class="pl-c1">&lt;</span><span class="pl-c1">/</span><span class="pl-ent">div</span><span class="pl-c1">&gt;</span>
  <span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Console log produces the following result:</p>
<div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="getData API call
CONTROLLER ABORT
getData API call
getData caught error
{err: CanceledError}
getData caught error
{err: CanceledError}"><pre class="notranslate"><span class="pl-c1">getData API call</span>
<span class="pl-c1">CONTROLLER ABORT</span>
<span class="pl-c1">getData API call</span>
<span class="pl-c1">getData caught error</span>
<span class="pl-c1">{err: CanceledError}</span>
<span class="pl-c1">getData caught error</span>
<span class="pl-c1">{err: CanceledError}</span></pre></div>
<h2 dir="auto">Link to code example:</h2>
<p dir="auto"><a href="https://codesandbox.io/s/react-18-abort-controller-bug-v3v4oi" rel="nofollow">https://codesandbox.io/s/react-18-abort-controller-bug-v3v4oi</a></p>
<h2 dir="auto">The current behavior</h2>
<p dir="auto">The second rendering of the component causes the controller to go from aborted false -&gt; true.</p>
<h2 dir="auto">The expected behavior</h2>
<p dir="auto">Please suggest how else can we use AbortController without duplicating logic and what are the best practices for doing so going forward.</p>
<p dir="auto">PS: I'm aware of the React.StrictMode <a href="https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state" rel="nofollow">changes in React 18</a>, but I can't seem to find another solution to this problem other than move all the fetch logic inside useEffect, which solves the problem, but cannot be isolated for reuse.</p>
<p dir="auto">Hi together</p>
<p dir="auto">Learning React at the moment and not sure if I'm not unterstanding a core part of React or this is a bug...</p>
<p dir="auto">My idea was to create a simple login and don't show the login window if the user is already logged in. Authentication is handled via Firebase, so here's a small snippet of my code:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="var Login = React.createClass ({

getInitialState: function(){
    return { loggedIn: false };
},

componentWillMount: function() {

    [ ... some firebase code ... ]

    firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
            this.setState({ loggedIn: true });
        }
        else {
            this.setState({ loggedIn: false });
        }

}

render: function() {
    return (
      &lt;div&gt;
      {this.state.loggedIn ? (
        &lt;div&gt;
        &lt;Backend/&gt;
        &lt;/div&gt;
      ) : (
         [ ... login form.... ]
      ) }
      &lt;/div&gt;
    );
  }
}); // END LOGIN
"><pre class="notranslate"><code class="notranslate">var Login = React.createClass ({

getInitialState: function(){
    return { loggedIn: false };
},

componentWillMount: function() {

    [ ... some firebase code ... ]

    firebase.auth().onAuthStateChanged(function(user) {
        if (user) {
            this.setState({ loggedIn: true });
        }
        else {
            this.setState({ loggedIn: false });
        }

}

render: function() {
    return (
      &lt;div&gt;
      {this.state.loggedIn ? (
        &lt;div&gt;
        &lt;Backend/&gt;
        &lt;/div&gt;
      ) : (
         [ ... login form.... ]
      ) }
      &lt;/div&gt;
    );
  }
}); // END LOGIN

</code></pre></div>
<p dir="auto">So my problem is the following: componentWillMount should be called before render, so if the user is already logged in, the new state is loggedIn: true and so it only renders the backend and not the login form... but unfortunately this new state in componentWillMount is not taken before render <strong>and it actually renders the login form</strong></p>
<p dir="auto">Thanks for the answer, cheers!</p>
<p dir="auto">Martin</p>