Can't Perform A React State Update On An Unmounted Component


Answer :

Here is a React Hooks specific solution for

Error

Warning: Can't perform a React state update on an unmounted component.

Solution

You can declare let isMounted = true inside useEffect, which will be changed in the cleanup callback, as soon as the component is unmounted. Before state updates, you now check this variable conditionally:

useEffect(() => {   let isMounted = true; // note this flag denote mount status   someAsyncOperation().then(data => {     if (isMounted) setState(data);   })   return () => { isMounted = false }; // use effect cleanup to set flag false, if unmounted }); 

const Parent = () => {   const [mounted, setMounted] = useState(true);   return (     <div>       Parent:       <button onClick={() => setMounted(!mounted)}>         {mounted ? "Unmount" : "Mount"} Child       </button>       {mounted && <Child />}       <p>         Unmount Child, while it is still loading. It won't set state later on,         so no error is triggered.       </p>     </div>   ); };  const Child = () => {   const [state, setState] = useState("loading (4 sec)...");   useEffect(() => {     let isMounted = true; // note this mounted flag     fetchData();     return () => {       isMounted = false;     }; // use effect cleanup to set flag false, if unmounted      // simulate some Web API fetching     function fetchData() {       setTimeout(() => {         // drop "if (isMounted)" to trigger error again         if (isMounted) setState("data fetched");       }, 4000);     }   }, []);    return <div>Child: {state}</div>; };  ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <div id="root"></div> <script>var { useReducer, useEffect, useState, useRef } = React</script>

Extension: Custom useAsync Hook

We can encapsulate all the boilerplate into a custom Hook, that just knows, how to deal with and automatically abort async functions in case the component unmounts before:

function useAsync(asyncFn, onSuccess) {   useEffect(() => {     let isMounted = true;     asyncFn().then(data => {       if (isMounted) onSuccess(data);     });     return () => { isMounted = false };   }, [asyncFn, onSuccess]); } 

// use async operation with automatic abortion on unmount function useAsync(asyncFn, onSuccess) {   useEffect(() => {     let isMounted = true;     asyncFn().then(data => {       if (isMounted) onSuccess(data);     });     return () => {       isMounted = false;     };   }, [asyncFn, onSuccess]); }  const Child = () => {   const [state, setState] = useState("loading (4 sec)...");   useAsync(delay, setState);   return <div>Child: {state}</div>; };  const Parent = () => {   const [mounted, setMounted] = useState(true);   return (     <div>       Parent:       <button onClick={() => setMounted(!mounted)}>         {mounted ? "Unmount" : "Mount"} Child       </button>       {mounted && <Child />}       <p>         Unmount Child, while it is still loading. It won't set state later on,         so no error is triggered.       </p>     </div>   ); };  const delay = () => new Promise(resolve => setTimeout(() => resolve("data fetched"), 4000));   ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <div id="root"></div> <script>var { useReducer, useEffect, useState, useRef } = React</script>


To remove - Can't perform a React state update on an unmounted component warning, use componentDidMount method under a condition and make false that condition on componentWillUnmount method. For example : -

class Home extends Component {   _isMounted = false;    constructor(props) {     super(props);      this.state = {       news: [],     };   }    componentDidMount() {     this._isMounted = true;      ajaxVar       .get('https://domain')       .then(result => {         if (this._isMounted) {           this.setState({             news: result.data.hits,           });         }       });   }    componentWillUnmount() {     this._isMounted = false;   }    render() {     ...   } } 

If above solutions dont work, try this and it works for me:

componentWillUnmount() {     // fix Warning: Can't perform a React state update on an unmounted component     this.setState = (state,callback)=>{         return;     }; } 

Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?