Checking if a component is unmounted using react hooks?

I wrote this custom hook that can check if the component is mounted or not at the current time, useful if you have a long running operation and the component may be unmounted before it finishes and updates the UI state.

import { useCallback, useEffect, useRef } from "react";

export function useIsMounted() {
  const isMountedRef = useRef(true);
  const isMounted = useCallback(() => isMountedRef.current, []);

  useEffect(() => {
    return () => void (isMountedRef.current = false);
  }, []);

  return isMounted;
}

Usage

function MyComponent() {
  const [data, setData] = React.useState()
  const isMounted = useIsMounted()

  React.useEffect(() => {
    fetch().then((data) => {
      // at this point the component may already have been removed from the tree
      // so we need to check first before updating the component state
      if (isMounted()) {
        setData(data)
      }
    })
  }, [...])

  return (...)
}

Live Demo

Edit 58979309/checking-if-a-component-is-unmounted-using-react-hooks


Please read this answer very carefully until the end.

It seems your component is rendering more than one time and thus the isMounted state will always become false because it doesn't run on every update. It just run once and on unmounted. So, you'll do pass the state in the second option array:

}, [isMounted])

Now, it watches the state and run the effect on every update. But why the first option works?

It's because you're using useRef and it's a synchronous unlike asynchronous useState. Read the docs about useRef again if you're unclear:

This works because useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.


BTW, you do not need to clean up anything. Cleaning up the process is required for DOM changes, third-party api reflections, etc. But you don't need to habit on cleaning up the states. So, you can just use:

useEffect(() => {
    setIsMounted(true)
}, []) // you may watch isMounted state
     // if you're changing it's value from somewhere else

While you use the useRef hook, you are good to go with cleaning up process because it's related to dom changes.