Skip to content

Instantly share code, notes, and snippets.

@btoo
Last active October 16, 2023 16:20
Show Gist options
  • Save btoo/5d01bc90657f6226f2eafcb0bd42ee03 to your computer and use it in GitHub Desktop.
Save btoo/5d01bc90657f6226f2eafcb0bd42ee03 to your computer and use it in GitHub Desktop.
Tired of seeing the `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.` error?
// Tired of seeing the
// `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.`
// error?
// Then use these utility hooks to make sure things don't happen in unmounted components!
import { useCallback, useEffect, useRef, useState } from "react";
import type { Dispatch, SetStateAction, DependencyList } from 'react'
export function useMountedRef() {
const mountedRef = useRef(true);
useEffect(function setMountedState() {
mountedRef.current = true;
return () => {
mountedRef.current = false;
};
});
return mountedRef;
}
/** same as `useState` except the `setState` only gets called if the component is still mounted */
export function useMountedState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
export function useMountedState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
export function useMountedState<S>(initialState?: S) {
const mountedRef = useMountedRef();
const [state, possiblyUnmountedSetState] = useState(initialState);
const setStateWhileMounted = useCallback((newState: S) => {
if (mountedRef.current) return possiblyUnmountedSetState(newState);
}, [possiblyUnmountedSetState]);
return [state, setStateWhileMounted] as const;
}
/** same as `useCallback` except the callback only gets called if the component is still mounted */
export function useMountedCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList) {
const mountedRef = useMountedRef();
return useCallback((...args: Parameters<T>) => {
if (mountedRef.current) return callback(...args);
}, deps);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment