Objects as useEffect deps
Some time ago my company decided to switch from native to React Native. For the last 2 years, I have gathered enough experience (I hope) to be able to say a word or two about React.
The first thing I want to cover is a common mistake developers make, even those who come from ReactJS. This mistake is about being not careful with useEffect's deps list.
How useEffect compares dependencies?
When a "dependency" from the deps list changes then useEffect will run. It does a ===
to check the change. The ===
is fine for strings, numbers, and booleans however for objects it only compares references, not actual equality.
This code will end up with an infinite useEffect increasing the counter. In this example, es-lint actually tells you going to have problems:
When it's safe to use an object with useEffect?
Not always passing an object into useEffect would end up with an infinite loop. useEffect uses ===
so as long as the object has a constant reference then you are safe.
State value from useState
has a constant reference until the setter is called. The same applies to a state from useReducer
or a state stored in Redux
. As long you are reading "state" objects, you should be safe.
useQuery
from Apollo also keeps constant reference (however I would assume the reference could change during a refetch even if the object has not changed in value)
Transformations - be careful
Sometimes, especially when the backend sends data in a weird format you may want to write a custom hook that would transform the response to a more frontend readable format:
Even that we have used useQuery
which returns a constant reference to its data, we still have an infinite the useEffect
. This is because of the transformation which happens inside useFetchPatient
. With transformations don't forget to wrap the transformed data with useMemo
:
Recap
When you work with useEffect
make sure values which are passed to its dependence have a constant reference. When that requirement is not met, expect your devices to become hot 🔥.
Feel free to play with the examples I have provided.
In the future article, I'm planning to cover how we can deal with callbacks passed to useEffect's deps. Sneak peek: useCallback
is the way, but IMO not the best one :)