Created
November 9, 2018 16:10
-
-
Save kentcdodds/fb8540a05c43faf636dd68647747b074 to your computer and use it in GitHub Desktop.
a custom react hook that I want feedback on because it feels like a lot of work and maybe I'm missing something...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Feedback requested on the useDeepCompareEffect | |
// it just feels like a bit of work... | |
// HERE'S THE REASON I NEED THIS: | |
// when people use the useQuery hook, they'll typically | |
// do so like this: `useQuery(myQuery, {var1: props.value})` | |
// which means that passing `variables` to `useEffect` will | |
// trigger a rerun of the callback even if they didn't | |
// actually change (referrential equality) | |
function useQuery({query, variables}) { | |
useDeepCompareEffect( | |
() => { | |
// make a request with the query and variables | |
}, | |
[query, variables], | |
) | |
// more stuff goes here... | |
} | |
function useDeepCompareEffect(callback, inputs) { | |
const previousInputs = usePrevious(inputs) | |
const inputsAreEqual = _.isEqual(inputs, previousInputs) | |
// every time our effect callback runs, the cleanup | |
// function for the effect will change. If we don't | |
// actually call the callback, then the user's cleanup | |
// function wont be updated. So we'll keep track of the | |
// most recent cleanup function and return that if | |
// we don't actually call the callback. | |
const cleanupRef = useRef() | |
useEffect( | |
() => { | |
if (!inputsAreEqual) { | |
cleanupRef.current = callback() | |
} | |
return cleanupRef.current | |
}, | |
// run the effect callback if equality changes | |
// this can change from [true] to [false] | |
// or from [false] to [true] | |
// both changes will cause the callback to re-run | |
// which is why we have the `if (!inputsAreEqual)` | |
// condition above. | |
[inputsAreEqual], | |
) | |
} | |
function usePrevious(value) { | |
const ref = useRef() | |
useEffect(() => { | |
ref.current = value | |
}) | |
return ref.current | |
} | |
// P.S. if you ask me what font/theme this is, what editor it is, | |
// or how I made this screenshot... I'm not going to answer. | |
// --> http://kcd.im/mft |
cdock1029
commented
Nov 9, 2018
I think this is the proper solution actually:
function useDeepCompareMemoize(value) {
const ref = React.useRef()
if (!_.isEqual(value, ref.current)) {
ref.current = value
}
return ref.current
}
function useDeepCompareEffect(callback, dependencies) {
React.useEffect(callback, useDeepCompareMemoize(dependencies))
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment