useIsMounted()

In React, once a component is unmounted, it is deleted from memory and will never be mounted again. That's why we don't define a state in a disassembled component. Changing the state in an unmounted component will result this error:

1Warning: Can't perform a React state update on an unmounted component.
2This is a no-op, but it indicates a memory leak in your application.
3To 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.

The Hook

1import { useCallback, useEffect, useRef } from 'react'
2
3function useIsMounted() {
4 const isMounted = useRef(false)
5
6 useEffect(() => {
7 isMounted.current = true
8
9 return () => {
10 isMounted.current = false
11 }
12 }, [])
13
14 return useCallback(() => isMounted.current, [])
15}
16
17export default useIsMounted

Usage

1import { useEffect, useState } from 'react'
2
3import { useIsMounted } from 'usehooks-ts'
4
5const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
6
7function Child() {
8 const [data, setData] = useState('loading')
9 const isMounted = useIsMounted()
10
11 // simulate an api call and update state
12 useEffect(() => {
13 void delay(3000).then(() => {
14 if (isMounted()) setData('OK')
15 })
16 }, [isMounted])
17
18 return <p>{data}</p>
19}
20
21export default function Component() {
22 const [isVisible, setVisible] = useState<boolean>(false)
23
24 const toggleVisibility = () => setVisible(state => !state)
25
26 return (
27 <>
28 <button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'}</button>
29
30 {isVisible && <Child />}
31 </>
32 )
33}

Edit on CodeSandbox

See a way to make this page better?
Edit there »