Skip to content

Instantly share code, notes, and snippets.

@Shrugsy
Last active November 24, 2022 18:13
Show Gist options
  • Save Shrugsy/5e898173c965e7642db8927636bedf7a to your computer and use it in GitHub Desktop.
Save Shrugsy/5e898173c965e7642db8927636bedf7a to your computer and use it in GitHub Desktop.
React hook that accepts a given callback, and provides a new callback with a stable reference, which will itself always call the latest version of the provided callback. Useful for dealing with third party components that use stale closures. Example: https://tsplay.dev/Bmx07m
import { useRef, useCallback} from 'react';
/**
* Accepts a given callback, and provides a new callback with a stable reference,
* which will itself always call the latest version of the provided callback.
* Useful for dealing with third party components that use stale closures.
* @param callback - the original callback desired to be called
* @returns A new callback with a stable reference, which when called,
* calls the latest provided callback
* @deprecated - This implementation may have future issues in concurrent mode, as it mutates
* the ref value during the render.
* It is expected that react will provide opportunities for better solutions in the future.
* See https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
*/
function useStableCallback<Args extends unknown[], Return>(callback: (...args: Args) => Return) {
const callbackRef = useRef(callback);
callbackRef.current = callback;
const stableCallback = useCallback((...args: Args) => {
return callbackRef.current(...args);
}, []);
return stableCallback;
}
@bjungs
Copy link

bjungs commented Nov 24, 2022

I'd like to contribute my own version of this.
The difference is that the function implementation will only be updated if the dependencies change.

Thanks for steering me in the right direction!

export function useMutableCallback(callback, deps = []) {
  const ref = useRef(() => {})

  useEffect(() => {
    ref.current = callback
  }, deps)

  return useCallback((...args) => ref.current(...args), [ref])
}

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