I have reviewed many posts attempting to resolve this issue and have tried numerous ways to take care of this error, but the answer stills eludes me. It is a common problem, I know, but my understanding of React appears to be inadequate to achieve resolution. I'm trying to eliminate this error:
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
I am unable to understand why componentWillUnmount does not resolve it. Here is the code:
import React from 'react';
import ReactDOM from 'react-dom';
export class PracticeData extends React.Component{
constructor(props){
super(props);
this.state = {
data: [],
isLoaded: false,
}
}
componentDidMount() {
this.mounted=true;
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => {
this.setState({ //triggers a rendering cycle
isLoaded: true,
data: json,
})
});
}
componentWillUnmount(){
this.isLoaded=false;
}
render(){
var { isLoaded, data } = this.state;
if(!isLoaded) {
return <div>Loading...</div>
} else {
return (
<div className="container-fluid">
<div className="row">{
data.map(data => <div key={data.id}>
<div className="list">
<li className="header">{data.name}</li>
<div className="body">
<li><strong>Company:</strong> {data.company.name}</li>
<li><strong>User Name: </strong> {data.username}</li>
<li><strong>Email: </strong> {data.email}</li>
<li><strong>Phone: </strong>{data.phone}</li>
</div>
<li className="address"><strong>Address: </strong></li>
<div className="body">
<li><strong>Street:</strong> {data.address.street}</li>
<li><strong>Suite: </strong> {data.address.suite}</li>
<li><strong>City: </strong> {data.address.city}<br/></li>
<li><strong>Zip Code:</strong> {data.address.zipcode}</li>
</div>
</div>
</div>
)}
</div>
</div>
);
}
}
}
ReactDOM.render(<PracticeData/>, document.getElementById('root'));
The fetch looks like the only thing that can possibly resolve after a component unmounts, and for this you'll need an AbortController.
Basic usage is
const controller = new AbortController();
const { signal } = controller;
fetch(url, { signal })
Later if needed, you can abort the fetch
controller.abort()
Update to your component
export class PracticeData extends React.Component{
constructor(props){
super(props);
this.state = {
data: [],
isLoaded: false,
}
}
controller = new AbortController();
componentDidMount() {
this.mounted=true;
const { signal } = this.controller;
fetch('https://jsonplaceholder.typicode.com/users', { signal }) // <-- pass signal in fetch options
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
data: json,
})
})
// catch any rejected fetch promises (including aborted fetches!)
.catch(console.error);
}
componentWillUnmount(){
this.isLoaded=false;
this.controller.abort(); // <-- abort any in-flight fetch requests
}
...
NOTE: fetch normally only returns rejected Promises for network errors, valis HTML error responses will return in resolved Promises. As noted in comment, aborted fetches will also return a rejection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With