Issue 1:
React version: 18.2

Steps To Reproduce

I have multiple async methods that fetch data from API on demand.

This data needs to be loaded initially on page load and also in case of refresh button pressed by the user

Without React.StrictMode the abort controller aborted = false

With React.StrictMode the abort controller gets set to aborted = true

Example code:

import { useEffect, useState } from "react";
import axios from "axios";

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

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

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

useEffect(() => {
getData();

return () => {
console.log("CONTROLLER ABORT");
controller.abort();
};
}, []);

const refreshData = async () => {
await getData();
};

return (
<div>
{data.length ? (
data.map((val) => val)
) : (
<div>{dataLoading ? "Loading..." : "Data not found."}</div>
)}
<Actions onRefresh={refreshData} />
</div>
);
}

function Actions({ onRefresh }) {
return (
<div style={{ marginTop: "20px" }}>
<button onClick={onRefresh}>Refresh</button>
</div>
);
}

Console log produces the following result:

getData API call
CONTROLLER ABORT
getData API call
getData caught error
{err: CanceledError}
getData caught error
{err: CanceledError}

Link to code example:

https://codesandbox.io/s/react-18-abort-controller-bug-v3v4oi

The current behavior

The second rendering of the component causes the controller to go from aborted false -> true.

The expected behavior

Please suggest how else can we use AbortController without duplicating logic and what are the best practices for doing so going forward.

PS: I'm aware of the React.StrictMode changes in React 18, 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.

Issue 2:
Hi together

Learning React at the moment and not sure if I'm not unterstanding a core part of React or this is a bug...

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:

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 (
<div>
{this.state.loggedIn ? (
<div>
<Backend/>
</div>
) : (
[ ... login form.... ]
) }
</div>
);
}
}); // END LOGIN

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 and it actually renders the login form

Thanks for the answer, cheers!

Martin