I've been using hooks for a while and I never fully understand why React is forcing me to includes some dependencies that I don't want on my useEffect.
The way I understand the 'dependencies' of a useEffect hook
Add the values you want to 'listen' whenever they change and trigger your effect. This works perfectly with a simple effect like:
import React, {useEffect, useState} from "react";
interface Props {
id: string
}
const SimpleComponent = (props: Props) => {
const {id} = props;
const [response, setResponse] = useState<object>();
useEffect(() => {
fetch(`https://myexample/${id}`)
.then(response => setResponse(response))
.catch(() => console.log("An error occurs!"))
}, [id])
return <div/>
};
However, there are some other cases where is not as straightforward as the example above. In this example we want to trigger the effect only when the id changes:
import React, {useEffect} from "react";
interface Props {
id: string
callback: Function
}
const SimpleComponent = (props: Props) => {
const {id, callback} = props;
useEffect(() => {
callback(id)
}, [id]);
return <div/>
};
In this example, I get the warning "React Hook useEffect has a missing dependency" it recommends to include 'callback' on the dependencies array (option 1) or remove the dependencies array (option 2).
Let's explore the recommendations:
Option 1 (Include 'callback' on the dependencies array): Including 'callback' on the dependencies array will cause my effect to trigger whenever the 'id' or the 'callback' changes. The problem with this is that I don't want to trigger the effect when the 'callback' changes cause the callback will change in every render.
Option 2 (remove the dependencies array): Removing the dependency array will cause my effect to trigger whenever the component changes which is not the wanted behavior either.
Other options found:
I've found some other advice from the community but all of them seem to not accomplish the wanted behavior. (https://stackoverflow.com/a/60327893/8168782)
Let's quickly review these options:
Option 1: Use an empty dependencies array:
It will only trigger when the component mounts, not what we want.
Option 2: Declare the function inside the useEffect()
In this case, the 'callback' is a function passed through props, but either way most of the time you can't declare the function inside the effect because the function is used in other places.
Option 3: Memoize with useCallback()
If you wrap your function inside a useCallback you also need to include the dependencies into the useCallback dependencies array, this will cause the useCallback to trigger again every time the dependencies change so the useEffect also will be triggered.
Option 4: Disable eslint's warnings
Not considered because I'm trying to understand the problem not simply ignore it.
I'm really confused about this warning, I don't know if there are some situations where the warning is wrong and should be ignored (what seems to be wrong) or that I'm missing something.