Skip to content

Instantly share code, notes, and snippets.

@rolandcoops
Created November 12, 2019 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rolandcoops/4364be2eff3586b0f8f3d0c10dc3be61 to your computer and use it in GitHub Desktop.
Save rolandcoops/4364be2eff3586b0f8f3d0c10dc3be61 to your computer and use it in GitHub Desktop.
Custom React hook for creating a stable callback reference that can be passed down as prop
// Taken (with some minor changes) from:
// https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
import { useRef, useEffect, useCallback } from 'react'
const throwReferenceError = () => {
throw new ReferenceError('Callback was called directly while rendering, pass it as a callback prop instead.')
}
/**
* Custom hook that wraps an unstable callback inside a stable wrapper callback.
* Useful to e.g. keep an event handler prop stable when passing it down.
*
* @param {Function} callback - unstable callback to be wrapped
* @param {Array} deps - list of values whose change will update the unstable callback reference (see React.useCallback)
* @returns {Function} stable wrapped callback
*
* @example
* // `handleClick` reference will not change even if deps change:
* const handleClick = useStableCallback((event) => {
* console.log(someDep, event.target)
* }, [someDep])
*/
const useStableCallback = (callback, deps) => {
const ref = useRef(throwReferenceError)
// update stored callback ref if callback or deps change
useEffect(() => {
ref.current = callback
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [callback, ...deps])
// return stable wrapped callback
return useCallback((...args) => {
ref.current(...args)
}, [ref])
}
export default useStableCallback
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment