Is there a way to check if the react component is unmounted?

JavascriptReactjs

Javascript Problem Overview


I have a usecase where i need to unmount my react component. But in some cases, the particular react component is unmounted by a different function. Hence, I need to check if the component is mounted before unmounting it.

Javascript Solutions


Solution 1 - Javascript

Since isMounted() is being officially deprecated, you can do this in your component:

componentDidMount() { 
  this._ismounted = true;
}

componentWillUnmount() {
   this._ismounted = false;
}

This pattern of maintaining your own state variable is detailed in the ReactJS documentation: isMounted is an Antipattern.

Solution 2 - Javascript

I'll be recommended you to use the useRef hook for keeping track of component is mounted or not because whenever you update the state then react will re-render the whole component and also it will trigger the execution of useEffect or other hooks.

function MyComponent(props: Props) {
  const isMounted = useRef(false)

  useEffect(() => {
    isMounted.current = true;
    return () => { isMounted.current = false }
  }, []);

  return (...);
}

export default MyComponent;

and you check if the component is mounted with if (isMounted.current) ...

Solution 3 - Javascript

I think that Shubham answer is a workaround suggested by react for people that need to transition their code to stop using the isMounted anti-pattern.

This is not necessarily bad, but It's worth listing the real solutions to this problem.

The article linked by Shubham offers 2 suggestions to avoid this anti pattern. The one you need depends on why you are calling setState when the component is unmounted.

> if you are using a Flux store in your component, you must unsubscribe in componentWillUnmount

class MyComponent extends React.Component {
  componentDidMount() {
    mydatastore.subscribe(this);
  }
  render() {
    ...
  }
  componentWillUnmount() {
    mydatastore.unsubscribe(this);
  }
}

> If you use ES6 promises, you may need to wrap your promise in order to make it cancelable.

const cancelablePromise = makeCancelable(
  new Promise(r => component.setState({...}}))
);

cancelablePromise
  .promise
  .then(() => console.log('resolved'))
  .catch((reason) => console.log('isCanceled', reason.isCanceled));

cancelablePromise.cancel(); // Cancel the promise

Read more about makeCancelable in the linked article.

In conclusion, do not try to patch this issue by setting variables and checking if the component is mounted, go to the root of the problem. Please comment with other common cases if you can come up with any.

Solution 4 - Javascript

Another solution would be using Refs . If you are using React 16.3+, make a ref to your top level item in the render function.

Then simply check if ref.current is null or not.

Example:

class MyClass extends React.Component {
  constructor(props) {
    super(props);
    this.elementRef = React.createRef();
  }

  checkIfMounted() {
     return this.elementRef.current != null;
  }

  render() {
    return (
      <div ref={this.elementRef} />
    );
  }
}

Solution 5 - Javascript

Using @DerekSoike answer, however in my case using useState to control the mounted state didn't work since the state resurrected when it didn't have to

What worked for me was using a single variable

myFunct was called in a setTimeout, and my guess is that when the same component initialized the hook in another page it resurrected the state causing the memory leak to appear again

So this didn't work for me

  const [isMounted, setIsMounted] = useState(false)

  useEffect(() => {
    setIsMounted(true)
    return () => setIsMounted(false)
  }, [])

  const myFunct = () => {
    console.log(isMounted) // not always false
    if (!isMounted) return
    // change a state
  }

And this did work for me

  let stillMounted = { value: false }
  useEffect(() => {
    stillMounted.value = true
    return () => (stillMounted.value = false)
  }, [])

  const myFunct = () => {
    if (!stillMounted.value) return
    // change a state
  }

Solution 6 - Javascript

If you're using hooks:

function MyComponent(props: Props) {
  const [isMounted, setIsMounted] = useState<boolean>(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  useEffect(() => {
    return () => {
      setIsMounted(false);
    }
  }, []);

  return (...);
}

export default MyComponent;

Solution 7 - Javascript

I got here because I was looking for a way to stop polling the API.

The react docs does cover the websocket case, but not the polling one.

The way I worked around it

// React component

React.createClass({
    poll () {
        if (this.unmounted) {
            return
        }
        // otherwise, call the api
    }
    componentWillUnmount () {
        this.unmounted = true
    }
})

it works. Hope it helps

Please, let me know if you guys know any failing test case for this =]

Solution 8 - Javascript

The same idea but enother implementation

/**
 * component with async action within
 * 
 * @public
 */
class MyComponent extends Component {
    constructor ( ...args ) {
        // do not forget about super =)
        super(...args);
        // NOTE correct store "setState"
        let originSetState = this.setState.bind(this);
        // NOTE override
        this.setState = ( ...args ) => !this.isUnmounted&&originSetState(...args);
    }
    /**
     * no necessary setup flag on component mount
     * @public
     */
    componentWillUnmount() {
        // NOTE setup flag
        this.isUnmounted = true;
    }
    /**
     *
     * @public
     */
    myCustomAsyncAction () {
        // ... code
        this.setState({any: 'data'}); // do not care about component status
        // ... code
    }

    render () { /* ... */ }
}

Solution 9 - Javascript

i found that the component will be unmounted, generate fill this var

if(!this._calledComponentWillUnmount)this.setState({vars});

Solution 10 - Javascript

You can use:

myComponent.updater.isMounted(myComponent)

"myComponent" is instance of your react component. this will return 'true' if component is mounted and 'false' if its not..

  • This is not supported way to do it. you better unsubscribe any async/events on componentWillUnmount.

Solution 11 - Javascript

I have solve with hot reload and react to different it events ✅

   const {checkIsMounted} = useIsMounted(); //hook from above
   useEffect(() => {
    //here run code
    return () => {
      //hot reload fix
      setTimeout(() => {
        if (!checkIsMounted()) {
          //here we do unmount action 
        }
      }, 100);
    };
  }, []); 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDharini SView Question on Stackoverflow
Solution 1 - JavascriptShubham KhatriView Answer on Stackoverflow
Solution 2 - JavascriptSagarView Answer on Stackoverflow
Solution 3 - JavascriptNicola PedrettiView Answer on Stackoverflow
Solution 4 - JavascriptTarun GehlautView Answer on Stackoverflow
Solution 5 - JavascriptGWorkingView Answer on Stackoverflow
Solution 6 - JavascriptDerek SoikeView Answer on Stackoverflow
Solution 7 - JavascriptmellocView Answer on Stackoverflow
Solution 8 - JavascriptSajera CoolView Answer on Stackoverflow
Solution 9 - JavascriptLeonardo OrozcoView Answer on Stackoverflow
Solution 10 - JavascriptDanny MichaeliView Answer on Stackoverflow
Solution 11 - JavascriptСтепан ТурченкоView Answer on Stackoverflow