Skip to content

Instantly share code, notes, and snippets.

@codemile
Created March 19, 2021 11:10
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save codemile/16999cb72adc2d736949f7605c8a7b8a to your computer and use it in GitHub Desktop.
Save codemile/16999cb72adc2d736949f7605c8a7b8a to your computer and use it in GitHub Desktop.
Here is a useSafeState hook that ignores state changes after a component has been unmounted.
import {
DependencyList,
Dispatch,
MutableRefObject,
SetStateAction,
useCallback,
useEffect,
useRef,
useState
} from 'react';
/**
* Returns a ref that indicates if the component has unmounted.
*/
export const useUnmounted = (): MutableRefObject<boolean> => {
const ref = useRef<boolean>(false);
useEffect(() => () => (ref.current = true), []);
return ref;
};
/**
* Returns a callback that only executes if the component is mounted.
*/
export const useSafeCallback = <T extends (...args: any[]) => any>(
callback: T,
deps: DependencyList
) => {
const unmounted = useUnmounted();
return useCallback(
(...args) => {
if (!unmounted.current && callback) {
callback(...args);
}
},
[callback, ...deps]
);
};
/**
* Returns a state hook that can safely be used after component is unmounted.
*/
export const useSafeState = <S,>(
initialState: S | (() => S)
): [S, Dispatch<SetStateAction<S>>] => {
const [value, setValue] = useState(initialState);
const safeValue = useSafeCallback(setValue, []);
return [value, safeValue];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment