Skip to content

Instantly share code, notes, and snippets.

@AlpacaGoesCrazy
Last active December 7, 2020 17:49
Show Gist options
  • Save AlpacaGoesCrazy/25e3a15fcd4e57fb8ccd408d488554d7 to your computer and use it in GitHub Desktop.
Save AlpacaGoesCrazy/25e3a15fcd4e57fb8ccd408d488554d7 to your computer and use it in GitHub Desktop.
Hook for react state which prevents updates on unmounted components
import { useEffect, useRef, useState } from 'react'
/*
If you attempt to set some state after asynchronous request it may happen that component you wish to set state on has been unmounted.
This will trigger "Warning: Can’t call setState (or forceUpdate) on an unmounted component." warning.
This hooks is `useState` hook which prevents setting state on an unmounted component
Usage:
const [myState, mySafeSetState] = useSafeState(initialValue)
*/
const useSafeState = (initialValue) => {
const _isMounted = useRef() // useRef to memorize if the component is mounted between renders
const [state, setState] = useState(initialValue)
useEffect(() => {
_isMounted.current = true
return () => {
_isMounted.current = false
}
})
const safeSetState = (...args) => {
if(_isMounted.current) { // do not call setState if the component already unmounted
setState(...args)
}
}
return [state, safeSetState]
}
export default useSafeState
@alexbepple
Copy link

alexbepple commented Dec 7, 2020

I have found that this does not preserve setState function identity (in contrast to React), which led to suprising bugs when replacing useState with useSafeState. I have therefore modified the implementation to:

export const useSafeState = (initialValue) => {
    const _isMounted = useRef();
    const [state, setState] = useState(initialValue);
    const _setState = useRef((...args) => {
        if (_isMounted.current) { setState(...args); }
    });

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment