Warning: 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 a useEffect cleanup function.
The right way to solve this is cleaning effect like the above message said.
For example, see useInterval or useEventListener.
But, there are some cases like Promise or API calls where it's impossible to know if the component is still mounted at the resolve time.
This React hook help you to avoid this error with a function that return a boolean, isMounted.
Usage
import { useEffect, useState } from 'react'
import { useIsMounted } from './useIsMounted'
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
function Child() {
const [data, setData] = useState('loading')
const isMounted = useIsMounted()
// simulate an api call and update state
useEffect(() => {
void delay(3000).then(() => {
if (isMounted()) setData('OK')
})
}, [isMounted])
return <p>{data}</p>
}
export default function Component() {
const [isVisible, setVisible] = useState<boolean>(false)
const toggleVisibility = () => {
setVisible(state => !state)
}
return (
<>
<button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'}</button>
{isVisible && <Child />}
</>
)
}
API
function useIsMounted(): () => boolean
Custom hook that determines if the component is currently mounted.
Returns
A function that returns a boolean value indicating whether the component is mounted.
Hook
import { useCallback, useEffect, useRef } from 'react'
/**
* Custom hook that determines if the component is currently mounted.
* @returns {() => boolean} A function that returns a boolean value indicating whether the component is mounted.
* @public
* @see [Documentation](https://usehooks-ts.com/react-hook/use-is-mounted)
* @example
* ```tsx
* const isComponentMounted = useIsMounted();
* // Use isComponentMounted() to check if the component is currently mounted before performing certain actions.
* ```
*/
export function useIsMounted(): () => boolean {
const isMounted = useRef(false)
useEffect(() => {
isMounted.current = true
return () => {
isMounted.current = false
}
}, [])
return useCallback(() => isMounted.current, [])
}