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'23function useIsMounted() {4 const isMounted = useRef(false)56 useEffect(() => {7 isMounted.current = true89 return () => {10 isMounted.current = false11 }12 }, [])1314 return useCallback(() => isMounted.current, [])15}1617export default useIsMounted
Usage
1import { useEffect, useState } from 'react'23import { useIsMounted } from 'usehooks-ts'45const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))67function Child() {8 const [data, setData] = useState('loading')9 const isMounted = useIsMounted()1011 // simulate an api call and update state12 useEffect(() => {13 void delay(3000).then(() => {14 if (isMounted()) setData('OK')15 })16 }, [isMounted])1718 return <p>{data}</p>19}2021export default function Component() {22 const [isVisible, setVisible] = useState<boolean>(false)2324 const toggleVisibility = () => setVisible(state => !state)2526 return (27 <>28 <button onClick={toggleVisibility}>{isVisible ? 'Hide' : 'Show'}</button>2930 {isVisible && <Child />}31 </>32 )33}
See a way to make this page better?
Edit there »