However, the compiler is complaining that I have a missing dependency
That is not a compiler error, it's an eslint warning.
ESLint is not very smart and does not know if something should be added as a dependency or not, so it defaults to warning you about potential problems and you are then free to disable this warning if you know that it does not apply to you.
Should you add navigate
to the list of dependencies when using it in useEffect
?
It depends.
The useNavigate()
hook depends on useLocation().pathname
+ a few other things.
So we can change the question to this:
Should your useEffect
hook run again if the path changes?
Reframing the question like this should make the answer more obvious for new devs.
Important note:
You will need to add navigate
as a dependency if you are navigating using relative paths.
This is because navigate
uses useLocation().pathname
to resolve relative paths.
In general I would advise against using relative paths when possible.
The accepted answer here says you should always add navigate
to the list of dependencies, but this can easily lead to problems that are hard to debug if you don't know that navigate
can change.
In most cases your component will only exist on one path, so it wont matter what you do.
The other people answering here apparently don't have much experience with react-router
, so they likely never encountered the case where the choice made a difference.
Anyway, here are your choices:
- Re-run the hook if path changes or if
props.nextPage
changes
const navigate = useNavigate();
useEffect(() => {
const timeout = setTimeout(() => navigate(props.nextPage), 3000);
return () => clearTimeout(timeout);
}, [navigate, props.nextPage]);
- Re-run the hook only if
props.nextPage
changes
const navigate = useNavigate();
useEffect(() => {
const timeout = setTimeout(() => navigate(props.nextPage), 3000);
return () => clearTimeout(timeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.nextPage]);
- Don't re-run the hook in any case (only run once)
const navigate = useNavigate();
useEffect(() => {
const timeout = setTimeout(() => navigate(props.nextPage), 3000);
return () => clearTimeout(timeout);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
Note about useEffect
callbacks:
- In order to reset the timeout when
useEffect
is re-run, I've added a callback that runs clearTimeout()
.
- You also need to cancel the timeout if the user decides not to wait and opens another page. For example, if you have a "Next" button then you will also need to cancel the timeout.
- Having this callback is also necessary if you have react strict mode enabled.
trying to make a loading/greeting page that navigates on to the next after a few seconds of being shown
I'm fairly sure you're not going to change the path or the nextPage prop during those few seconds, so in your case it won't make a difference whether you add the dependencies or not.
The only reason why I can suggest adding variables even when they are not necessary is because disabling eslint warnings will make it more likely that you forget to add variables that do change.