Nice examples! I'm sure that you are aware of it, and know how to fix it. So for anyone else reading the article and my comment here: there's a small problem with the useFetch hook implementation.
It currently would not react to URL or options argument changes, since the internally used useEffect doesn't specify them as dependencies, so the response result wouldn't change should the request change (e.g. different URL or different query parameters). In fact fetch only runs once on component mount, because the dependencies array is empty.
In order to fix that the url and the options need to be added to the dependencies array as follows:
useEffect(() => {
...run fetch, store result...
}, [url, options]);
Referential Equality Problem
The problem with React dependencies is that changes are detected through referential equality tests. So a hook with dependencies only gets re-run when the following is true for one or more of the dependency values:
before !== after
That works fine for primitive values such as numbers, strings and booleans.
In case of functions or objects such as the options parameter this is a bit of a problem. Even when the data in an object literal does not change, two instances of {} are not referentially equal. JavaScript would create new instances for those object literals on each render run.
Three workarounds for that:
Let the user of useFetch take care of memoizing the options via useMemo, so it's "referentially stable" and does not change from render run to render run. But that would be sorting out the problem from the wrong end in my opinion
From within useFetch, serialize the options argument as string, and add that string to the dependencies array. The serialization must be stable though, so we don't get different results between render runs (i.e. different order of properties)
Use an use effect hook that is able to do deep dependency comparisons. Let's call it useEffectDeep. That could be either an exercise for writing another custom hook, or can be downloaded from here (or other places): github.com/kentcdodds/use-deep-com...
Nice examples! I'm sure that you are aware of it, and know how to fix it. So for anyone else reading the article and my comment here: there's a small problem with the
useFetch
hook implementation.It currently would not react to URL or options argument changes, since the internally used
useEffect
doesn't specify them as dependencies, so the response result wouldn't change should the request change (e.g. different URL or different query parameters). In fact fetch only runs once on component mount, because the dependencies array is empty.In order to fix that the url and the options need to be added to the dependencies array as follows:
Referential Equality Problem
The problem with React dependencies is that changes are detected through referential equality tests. So a hook with dependencies only gets re-run when the following is true for one or more of the dependency values:
That works fine for primitive values such as numbers, strings and booleans.
In case of functions or objects such as the options parameter this is a bit of a problem. Even when the data in an object literal does not change, two instances of
{}
are not referentially equal. JavaScript would create new instances for those object literals on each render run.Three workarounds for that:
Let the user of
useFetch
take care of memoizing the options viauseMemo
, so it's "referentially stable" and does not change from render run to render run. But that would be sorting out the problem from the wrong end in my opinionFrom within
useFetch
, serialize the options argument as string, and add that string to the dependencies array. The serialization must be stable though, so we don't get different results between render runs (i.e. different order of properties)Use an use effect hook that is able to do deep dependency comparisons. Let's call it
useEffectDeep
. That could be either an exercise for writing another custom hook, or can be downloaded from here (or other places): github.com/kentcdodds/use-deep-com...🔥🔥
Awesome, thank you very much for the detailed analysis!